1. 程式人生 > >Codechef:Easy exam(斯特林數)

Codechef:Easy exam(斯特林數)

傳送門

題解:
x j , i x_{j,i} 表示第 j

j 輪擲骰子擲出 i i 。則 a n s =
i = 1 L (
j = 1 n
x j , i ) F ans=\prod_{i=1}^L(\sum_{j=1}^nx_{j,i})^F

然後展開考慮單項貢獻,顯然一個單項式對於一個 i i 如果有 j j 輪的 x j , i x_{j,i} 出現,貢獻為 S F , z n z S_{F,z}n^{\underline{z}}

當然不能選重複的,所以需要做一個揹包,此時發現 n p 0 ( m o d p ) n^{\underline{p}} \equiv 0 \pmod{p} ,所以只需要存 p p 項。 用倍增FFT即可做到 O ( p log p log L ) O(p\log p \log L) ,如果你會多項式exp當然也可以做到 O ( p log p ) O(p \log p) 不過我選擇樸素的揹包,時間複雜度 O ( F L p ) O(F*L*p)

#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();
}