Codechef:Easy exam(斯特林數)
阿新 • • 發佈:2018-11-01
題解:
記
表示第
輪擲骰子擲出
。則
然後展開考慮單項貢獻,顯然一個單項式對於一個 如果有 輪的 出現,貢獻為 。
當然不能選重複的,所以需要做一個揹包,此時發現
,所以只需要存
項。 用倍增FFT即可做到
,如果你會多項式exp當然也可以做到
。不過我選擇樸素的揹包,時間複雜度
。
#include <bits/stdc++.h>
using namespace std;
const int mod=2003;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (long long)x*y%mod;}
inline int power(int a,int b,int rs=1) {for(;b;b>>=1,a=mul(a,a)) if(b&1) rs=mul(rs,a); return rs;}
inline int inv(int a) {return power(a,mod-2);}
const int N=5e4+50, M=2e3+50;
int n,k,L,F,f[M];
struct combin {
int S[M][M], pd[M];
combin() {
S[0][0]=S[1][1]=1;
for(int i=2;i<M;i++)
for(int j=1;j<=i;j++)
S[i][j]=add(S[i-1][j-1],mul(j,S[i-1][j]));
}
inline void init() {
pd[0]=1;
for(int i=1;i<=mod;i++) pd[i]=mul(pd[i-1],n-i+1);
}
} C;
struct poly {
vector <int> a;
poly(int t=0) {a.resize(1); a[0]=t;}
inline int deg() const {return a.size()-1;}
friend inline poly operator *(const poly &a,const poly &b) {
poly c; c.a.resize(min(a.deg()+b.deg()+1,mod));
for(int i=0;i<=a.deg();i++)
for(int j=0;j<=b.deg() && i+j<mod;j++)
c.a[i+j]=add(c.a[i+j],mul(a.a[i],b.a[j]));
if(c.deg()>=mod) c.a.resize(mod);
return c;
}
inline void init() {
a.resize(F+1);
for(int i=0;i<=F;i++) a[i]=C.S[F][i];
}
inline void pt() {
for(int i=0;i<=deg();i++) cout<<a[i]<<' '; cout<<"\n\n";
}
} g;
inline void solve() {
cin>>n>>k>>L>>F; C.init();
poly f(1),g; g.init();
int b=L;
for(;b;b>>=1,g=g*g)
if(b&1) f=f*g;
int ans=0, iv=inv(k);
for(int i=L,j=power(iv,i-1);i<=f.deg();i++) {
j=mul(j,iv);
ans=add(ans,mul(j,mul(C.pd[i],f.a[i])));
}
cout<<ans<<'\n';
}
int main() {
int T; cin>>T;
while(T--) solve();
}