高精度数学-洛谷P1066 2^k进制数
https://daniu.luogu.org/problem/show?pid=1066
我一开始题目全没看懂,然后去问Fop_zz,后来才知道化成二进制后可能缺的部分是在前面的;
。。。
我一直以为是在后面的;
…….
r的每一位对应q的k位,设len=w/k,当k|w时,r的位数可以从2到len,且无大小限制,当w%k≠0时,r的位数可以从2到len+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);
}