[SHOI2015]超能粒子炮·改
推柿子。
\[f(n,k)
\]
\[=\sum\limits_{i=1}^kC_n^i\%P
\]
\[=\sum\limits_{i=1}^kC_{n/P}^{i/P}\times C_{n\%P}^{i\%P}\%P
\]
\[=\sum\limits_{k=0}^{\lfloor\frac{k}{P}\rfloor-1}C_{\lfloor\frac{n}{P}\rfloor}^k\times\sum\limits_{j=0}^{P-1}C_{n\%P}^j+C_{\lfloor\frac{n}{P}\rfloor}^{\lfloor\frac{k}{P}\rfloor}\sum\limits_{j=0}^{k\%P}C_{n\%P}^j
\]
\[=f(n/P,k/P-1)\times f(n\%P,P-1)+C_{n/P}^{k/P}f(n\%P,k\%P)
\]
然后就可以递归处理了。边界特判比较特殊,当两个参数有一个小于0时要返回0,而且lucas函数里一定要取模(调了半天),再有就是当m小于n时f(m,n)是有值的。
code:
#include<bits/stdc++.h>
//#define zczc
#define int long long
const int N=3010;
const int mod=2333;
using namespace std;
inline void read(int &wh){
wh=0;int f=1;char w=getchar();
while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
wh*=f;return;
}
int c[N][N],s[N][N];
inline int lucas(int s1,int s2){
if(s1<s2)return 0;
if(s1<mod&&s2<mod)return c[s1][s2];
return lucas(s1/mod,s2/mod)*lucas(s1%mod,s2%mod)%mod;
}
inline int f(int m,int n){
//printf("now:%lld %lld\n",m,n);
if(m==0||n==0)return 1;
if(m<0||n<0)return 0;
if(m<mod&&n<mod){
//if(m<0||n<0)printf("rr:%lld %lld\n",m,n);
return s[m][n];
}
//if(lucas(m/mod,n/mod)<0)printf("wrong\n");
return (f(m/mod,n/mod-1)*f(m%mod,mod-1)+lucas(m/mod,n/mod)*f(m%mod,n%mod))%mod;
//int ans=(f(m/mod,n/mod-1)*f(m%mod,mod-1)+lucas(m/mod,n/mod)*f(m%mod,n%mod))%mod;
//int s1=f(m/mod,n/mod-1),s2=f(m%mod,mod-1),s3=f(m%mod,n%mod);
//if(ans<0)printf("%lld %lld %lld %lld %lld\n",s1,s2,lucas(m/mod,n/mod),s3,ans);
}
signed main(){
#ifdef zczc
freopen("in.txt","r",stdin);
#endif
c[0][0]=s[0][0]=1;
for(int i=1;i<mod;i++){
for(int j=0;j<mod;j++){
c[i][j]=((j?c[i-1][j-1]:0)+c[i-1][j])%mod;
s[i][j]=(j==0?1:s[i][j-1]+c[i][j])%mod;
//if(c[i][j]<0||s[i][j]<0)printf("wrong\n");
}
}
//printf("cc:%lld\n",s[1476][2332]);
int T,m,n;read(T);
while(T--){
read(m);read(n);
//if(f(m,n)<0);//printf("nnnn in %lld\n",T);
printf("%lld\n",f(m,n));
}
return 0;
}
一如既往,万事胜意