题解:P16781 ⌈Xzy OI R1 T3⌋ 穿穿表
很牛的题啊。
我们注意到部分分给出了
k=0
其实就是
k\le 100
设答案的值为
观察一下当前的式子:
我们知道
所以上面的式子变为了(根据题意当
再拆开并整理一下:
我们发现左边的式子恰好为
由于
这一部分复杂度为
k>100
我们注意到这时抛开组合数的复杂度不谈,直接枚举的复杂度是
那么我们考虑怎么求巨大的组合数,我们注意到题目给出一下提示:
这十分有用!这告诉我们可以直接使用 Lucas 定理,而 Lucas 定理的复杂度为预处理
这一部分复杂度为
于是我们就通过了这一题,注意卡常。
代码
const int N=101,M=1145141;
int n;
struct mat{
int c[N][N];
int * operator[](int i){
return c[i];
}
void clear(){
memset(c,0,sizeof c);
}
void init(){
clear();
for(int i=0;i<N;i++)c[i][i]=1;
}
friend mat operator *(mat a,mat b){
mat c;c.clear();
for(int k=0;k<n;++k){
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
c[i][j]=(c[i][j]+1ll*a[i][k]*b[k][j]%M)%M;
}
}
}return c;
}
friend mat operator ^(mat a,int b){
mat ret;ret.init();
while(b){
if(b&1)ret=ret*a;
a=a*a;
b>>=1;
}return ret;
}
}A,B;
int qpow(int a,int b){
int ret=1;
while(b){
if(b&1)ret=1ll*ret*a%M;
a=1ll*a*a%M;
b>>=1;
}return ret;
}
int fac[2000000],inv[2000000];
inline int C(int n,int m){
if(m>n)return 0;
return 1ll*fac[n]*inv[m]%M*inv[n-m]%M;
}
inline int Lucas(int n,int m,int p){
if(!m)return 1;
return (1ll*Lucas(n/p,m/p,p)*C(n%p,m%p))%p;
}
main(){
int k,b;
cin>>k>>b;
if(b<=k){
cout<<1;
return 0;
}
if(k==0)cout<<qpow(2,b);
else if(k<=100){
n=k+1;
for(int i=0;i<=k;i++)A[0][i]=1;
for(int i=0;i<k;i++)B[i+1][i]=1;
B[0][k]=1;
B[k][k]=1;
A=A*(B^b-k);
cout<<A[0][k];
}else{
fac[0]=1;
for(int i=1;i<1145141;++i)fac[i]=1ll*fac[i-1]*i%M;
inv[1145140]=qpow(fac[1145140],M-2);
for(int i=1145140;i;--i)inv[i-1]=1ll*inv[i]*i%M;
int ans=0;
for(int i=0;1ll*i*k<=1ll*b;++i)ans=(Lucas(b-i*k,i,M)+ans)%M;
cout<<ans;
}return 0;
}