NOIP 2006 提高组 复赛 digital 2k 进制数

来源:互联网 发布:pyqt5 tabwidget数据 编辑:程序博客网 时间:2024/05/16 05:50

NOIP 2006 提高组 复赛 digital 2k 进制数

//洛谷 P1066 2^k进制数
//提示:作为结果的正整数可能很大,但不会超过200位,考虑用高精度算法,加
//没什么思路,翻看他人做法,积累经验,该题还考什么,排列组合,猜测。
//http://hzwer.com/794.html此文写得不错,同时,也应证了本人的想法。
//自个举了个例子3 8
//2位 C[7][2]=21
//3位 首位最大值(11)2 (3)10 C[6][2]+c[5][2]+c[4][2]=31
//首位放1 C[6][2]  2 c[5][2]  3 c[4][2]
//组合数公式,可以由杨辉三角而来,c[i][j]=c[i-1][j]+c[i-1][j-1];
//突然意识到,用高精度算法的程序,测试起来极其困难。但还是找到了测试办法,不打印测试数据,打印要计算的数据
//提交,全报MLE,没辙,将 int c[520][520][210];改成int c[520][520][100];
//c[0][0][0]=1,c[0][0][1]=0;//更改此句memset(c,0,sizeof(c));算法效率立马得到了极大的提高,由2637ms提高到45ms
//该题疑问,数组最大能开到多大,或者说内存大小如何计算。猜测10^7到10^8之间,待日后查证
//该题耗时4天,主要时间花在理解 除首位计数情况,包含首位计数情况。2017-5-17 AC

#include <stdio.h>
#include <string.h>
int c[520][520][100];//标准是512 512 200现在安排有一定弹性空间,隐忧,容易内存溢出
int ans[210];
void plus1(int x[],int y[],int z[]){//3 z[0]存储数据长度,z[1]是最低位,打印注意,要从最高位打起
    int i;
    z[0]=x[0]>y[0]?x[0]:y[0];
    for(i=1;i<=z[0];i++){
        z[i]+=x[i]+y[i];
        z[i+1]=z[i]/10;//进位, 2 此处写成 z[i+1]=z[i]%10;
        z[i]%=10;//2 此处写成 z[i]/=10;  
    }
    if(z[z[0]+1]>0)
        z[0]++;//当前数据长度
}
void plus2(int x[],int y[]){
    int i;
    x[0]=x[0]>y[0]?x[0]:y[0];
    for(i=1;i<=x[0];i++){
        x[i]+=y[i];
        x[i+1]+=x[i]/10;//4 此处写成x[i+1]+=x[i]/10 进位,2 此处写成  x[i+1]=x[i]%10;
        x[i]%=10;//2 此处写成  x[i]/=10;
    }
    if(x[x[0]+1]>0)
        x[0]++;//当前数据长度
}
int main(){
    int k,w,b,h,i,j;
    scanf("%d%d",&k,&w);
    b=1<<k;
    h=1<<w%k;
    c[0][0][0]=1,c[0][0][1]=0;//更改此句memset(c,0,sizeof(c));算法效率立马得到了极大的提高,由2637ms提高到45ms
    memset(ans,0,sizeof(ans));
    for(i=1;i<b;i++)//打表,排列组合
        for(j=0;j<=i;j++)//1此处写成for(j=0;j<i;j++)
            if(j==0||i==j){//此句写得很棒,配合上c[0][0][0]=1,c[0][0][1]=0;对于 c[i][j]=c[i-1][j]+c[i-1][j-1];计算,无懈可击.自认为关于组合数的计算,这个写法是相当棒的。
                c[i][j][0]=1;//数据长度
                c[i][j][1]=1;//初始数据为1
            }else
                plus1(c[i-1][j],c[i-1][j-1],c[i][j]);
    for(i=2;i<=w/k&&i<b;i++)//除首位的情况 i<=w/k除首位情况,i<b若位数比较多,不能超越可选数字个数b-1
        plus2(ans,c[b-1][i]);
    for(i=1;i<h&&i+w/k<b;i++)//有首位的情况 i<h在首位里取1,2,...,h-1的情况,同时总需求个数i+w/k不能超越数字个数b-1
        plus2(ans,c[b-1-i][w/k]);//4 此处写成 plus2(ans,c[b-1-i][i]);
    for(i=ans[0];i>=1;i--)//3 z[0]存储数据长度,z[1]是最低位,打印注意,要从最高位打起 此处写成 for(i=1;i<=ans[0];i++)
        printf("%d",ans[i]);
    printf("\n");
    return 0;
}


0 0
原创粉丝点击