zoukankan      html  css  js  c++  java
  • P1066 2^k进制数

    传送门

    好好看题

    看懂了就不难了

    在2^k进制下,一位一位看

    每一位都有一些数可以填

    除非是最左边一位,不然可以填的数最大都是 2^k-1

    所以显然当填的位数为 i 时(不是最后一位),可能的选取方案总共有 C(2^k-1,i )

    如果要填最后一位

    最后一位可以填的最大的数为 2^ (w%k)-1

    那就枚举一下最后的数,前面选取的数都要大于它

    那么当最后的数为 i 时,前面的数选取方案数为 C( (2^k-1) -i,w/k)

    (注意 w/k 可能很大,但是如果超过 2^9-1 那就没意义了(能够选的数最大只有 2^9-1))

    因为答案很大,要用高精度

    我用的是压位高精(借着这一题学了一下压位高精...)

    (感谢crk大佬为我提供压位高精的代码 %%%)

    最后要注意一下细节

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int wid=10000;//压位高精,每4位放一起
    struct data
    {
        int a[52],len;
        data(){ memset(a,0,sizeof(a)); len=0; }
        //初始化
        data operator + (data &tmp)//重载加号
        {
            data u; int x=0;
            u.len= len>tmp.len ? len : tmp.len;
            for(int i=1;i<=u.len;i++)
            {
                u.a[i]=a[i]+tmp.a[i]+x;
                x=u.a[i]/wid; u.a[i]%=wid;
            }
            while(x) u.a[++u.len]=x%wid,x/=wid;
            return u;
        }
        data operator * (data &tmp)
        //重载乘号,其实用不上,顺便一起打了
        {
            data u; int x=0;
            for(int i=1;i<=tmp.len;i++,x=0)
            {
                for(int j=1;j<=len;j++)
                {
                    u.a[i+j-1]+=tmp.a[i]*a[j]+x;
                    x=u.a[i+j-1]/wid; u.a[i+j-1]%=wid;
                }//注意细节
                u.a[i+len]+=x;
            }
            while(u.a[u.len+1]) u.a[u.len+2]+=u.a[u.len+1]/wid,u.a[(++u.len)+1]%=wid;
            //一堆细节..
            return u;
        }
        void print()
        {
            printf("%d",a[len]);
            for(int i=len-1;i;i--)
            {
                for(int j=10;j*a[i]<wid;j*=10) printf("0");
                //如果压的数还不到4位就要补上0
                printf("%d",a[i]);
            }
        }
    }C[513][513],ans;
    int k,w,n,p;
    int main()
    {
        scanf("%d%d",&k,&w);
        n=(1<<k)-1; p=w/k>512 ? 512 : w/k;//p最大为512
    
        for(int i=0;i<=n;i++) C[i][0].a[1]=1,C[i][0].len=1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=i;j++)
                C[i][j]=C[i-1][j-1]+C[i-1][j];
        //求组合数
        for(int i=2;i<=p;i++) ans=ans+C[n][i];
        for(int i=(1<<w%k)-1;i;i--) ans=ans+C[n-i][p];//i不能取0,细节
        ans.print();
        return 0;
    }
  • 相关阅读:
    九度oj 题目1525:子串逆序打印
    九度oj 题目1516:调整数组顺序使奇数位于偶数前面
    九度oj 题目1490:字符串链接
    九度oj 题目1438:最小公倍数
    九度oj 题目1181:遍历链表
    九度oj 题目1179:阶乘
    九度oj 题目1077:最大序列和
    九度oj 题目1075:斐波那契数列
    九度oj 题目1074:对称平方数
    九度oj 题目1073:杨辉三角形
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9605859.html
Copyright © 2011-2022 走看看