高精度数学-洛谷P1066 2^k进制数

https://daniu.luogu.org/problem/show?pid=1066
我一开始题目全没看懂,然后去问Fop_zz,后来才知道化成二进制后可能缺的部分是在前面的;
。。。
我一直以为是在后面的;
…….

r的每一位对应q的k位,设len=w/k,当k|w时,r的位数可以从2len,且无大小限制,当w%k≠0时,r的位数可以从2len+1,但首位<2^(w%k)。

设位数为l。

1) l≤len时,相当于从2^k-1个数中选l个数然后升序排列,有C(2^k-1,l)种,总共有ΣC(2^k-1,i) (2≤i≤len)种。

2) l=len+1时,首位<2^(w%k),其后的数必须大于首位,相当于从2^k-1-i个数中选len个数升序排列,总共有ΣC(2^k-1-i,len) (1≤i<2^(w%k))种。

k|w时只有第一种。

接下来就是高精了……用杨辉三角:C(m+1,n+1)=C(m,n)+C(m,n+1)。

这是洛谷(深海鱼的眼泪)的题解;
里面的k就是题目的k;
那个为什么C(2^k-1,i)是2^k-1,因为0不能取;
我们从小到大,那么第一位不可以是0,显然就是不可取的;
所以减1啊;
C(2^k-1-i,len)
这个因为我们的那个二进制串最前面可能取不到k个,前面是最小的,所以后面显然可以取2^k-1-i个数;
然后就是高精度了;
我被卡内存了55555

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define Ll long long
using namespace std;
const Ll NN=1e9;
const int N=9;
struct H{
    Ll a[15],len;
    H(){memset(a,0,sizeof a);len=1;}
    void clear(){memset(a,0,sizeof a);len=1;}
};
int n,m,len,K,w;
H C[513][600],ans;
void outit(H a){
    printf("%lld",a.a[a.len]);
    for(int i=a.len-1;i;i--){
        for(int k=NN/10;a.a[i]<k;k/=10)printf("0");
        if(a.a[i])printf("%lld",a.a[i]); 
    }printf("\n");  
}
H in(int x){
    H a;
    if(!x)return a;
    a.len=0;
    while(x){a.a[++a.len]=x%NN;x=x/NN;}
    return a;
}
H jia(H a,H b){
    H c;
    int l=max(a.len,b.len);
    for(int i=1;i<=l;i++){
        c.a[i]+=a.a[i]+b.a[i];
        c.a[i+1]=c.a[i]/NN;
        c.a[i]%=NN;
    }
    if(c.a[l+1])l++;
    c.len=l;
    return c;
}
int main()
{
    scanf("%d%d",&n,&w);
    len=w/n;
    m=w%n;
    K=1<<n;
    for(int i=1;i<=K;i++)
    for(int j=0;j<=i;j++)
        if(j==0||j==i)C[i][j]=in(1);else
        C[i][j]=jia(C[i-1][j-1],C[i-1][j]);
    for(int i=2;i<=len;i++)ans=jia(C[K-1][i],ans);
    for(int i=1;i<(1<<m);i++)ans=jia(C[K-1-i][len],ans);
    outit(ans);
}
posted @ 2017-03-31 14:46  largecube233  阅读(150)  评论(0编辑  收藏  举报