bzoj1902【Zju2116】 Christopher
题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1902
sol :一眼可以看出此题应用了lucas定理(逃~
将n,m都化为p进制,记为a[],b[]
则对于我们所求的C(n,m)%p,有C(n,m)=∏ (i from 1 to n) (p^i)*(C(a[i],b[i]))%p
若C(n,m)为p的倍数,则存在某一位b[i]>a[i]
即此题要求有多少个<n的数,且其p进制下存在某一位比n的p进制的对应位大
求出a[]后直接数位dp即可
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; const int Mx=510; struct Node { int n,g[505]; void pre(int k) {n=1; g[1]=k;} Node operator*(const int &b) { Node c; int y=0; c.n=n; if(!b) { c.pre(0); return c; } for(int i=1;i<=n;i++) { y+=g[i]*b; c.g[i]=y%10; y/=10; } while(y) { c.g[++c.n]=y%10; y/=10; } return c; } Node operator+(const Node &b) { Node c; int y=0,p; if(n>b.n) { c.n=n; for(int i=1;i<=n;i++) c.g[i]=g[i]; p=b.n; for(int i=1;i<=b.n;i++) { y+=b.g[i]+c.g[i]; c.g[i]=y%10; y/=10; } while(y&&p<n) { y+=c.g[++p]; c.g[p]=y%10; y/=10; } } else { c.n=b.n; for(int i=1;i<=b.n;i++) c.g[i]=b.g[i]; p=n; for(int i=1;i<=n;i++) { y+=g[i]+c.g[i]; c.g[i]=y%10; y/=10; } while(y&&p<b.n) { y+=c.g[++p]; c.g[p]=y%10; y/=10; } } if(y) c.g[++c.n]=y; return c; } int operator/(const int &b) { int y=0; for(int i=n;i>=1;i--) { y=y*10+g[i]; if (y<b) g[i]=0; else {g[i]=y/b; y%=b;} } while(n>1&&!g[n]) n--; return y; } void read() { char s[Mx]; scanf("%s",s+1); n=strlen(s+1); for(int i=1;i<=n;i++) g[n+1-i]=s[i]-'0'; } } x,mul,ans,f[Mx]; int p,a[Mx],cnt; int main() { x.read(); scanf("%d",&p); while(x.n!=1||x.g[1]) a[++cnt]=x/p; f[0].pre(0),mul.pre(1),ans.pre(0); for(int i=1;i<cnt;i++) { f[i]=mul*(p-1-a[i]); f[i]=f[i]+f[i-1]*(a[i]+1); mul=mul*p; } for(int i=cnt;i>1;i--) ans=ans+f[i-1]*a[i]; for(int i=ans.n;i>=1;i--) printf("%d",ans.g[i]); return 0; }