Description
题解
upd:原来这是二项式反演来着qwq…
贴一下容斥题的一点点做法.
首先显然先求方案数 g [ i ] g[i] g[i]表示只有 i i i种出现了 S S S次的方案数
那怎么说也要求一个 f [ i ] f[i] f[i]表示至少有 i i i种出现了 S S S次的方案数
f [ i ] = C m i ∗ C n i ∗ S ∗ ( i ∗ S ) ! i n v [ S ] i ∗ ( m − i ) n − i ∗ S f[i]=C_m^i*C_n^{i*S}*\frac{(i*S)!}{inv[S]^i}*(m-i)^{n-i*S} f[i]=Cmi∗Cni∗S∗inv[S]i(i∗S)!∗(m−i)n−i∗S
i n v [ S ] inv[S] inv[S]表示 S ! S! S!的逆元
我们写一下一个东西,竖行表示 g g g,横行表示 f f f
注意到这是一个倒三角
中间的东西表示会被算几次
那么 后面的系数是可以从上一行推下来的
要记住容斥的这种推系数做法啊
那么式子就有了
g [ i ] = ∑ j = i ( − 1 ) j − i ∗ C j i ∗ f [ j ] g[i]=\sum_{j=i} (-1)^{j-i}*C_j^i*f[j] g[i]=j=i∑(−1)j−i∗Cji∗f[j]
把组合数拆开
g [ i ] = ∑ j = i ( − 1 ) j − i ∗ j ! i ! ( j − i ) ! ∗ f [ j ] g[i]=\sum_{j=i}(-1)^{j-i}*\frac{j!}{i!(j-i)!}*f[j] g[i]=j=i∑(−1)j−i∗i!(j−i)!j!∗f[j]
把 i ! i! i!移项, j ! j! j!扔到 f [ j ] f[j] f[j]里面可以知道
g [ i ] ∗ i ! = ∑ j = i ( − 1 ) j − i ( j − i ) ! ∗ f [ j ] ∗ j ! g[i]*i!=\sum_{j=i}\frac{(-1)^{j-i}}{(j-i)!}*f[j]*j! g[i]∗i!=j=i∑(j−i)!(−1)j−i∗f[j]∗j!
后面那个项把 ( − 1 ) j − i ( j − i ) ! \frac{(-1)^{j-i}}{(j-i)!} (j−i)!(−1)j−i反项,就可以直接卷积求出来了
注意预处理的复杂度要压到 m a x ( n , m ) max(n,m) max(n,m)不然bz会跪…
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(int x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
const int mod=1004535809;
const int MAXN=100005;
const int MAXM=10000005;
int pow_mod(int a,int b)
{
int ret=1;
while(b)
{
if(b&1)ret=1LL*ret*a%mod;
a=1LL*a*a%mod;b>>=1;
}
return ret;
}
int A[MAXN*4],B[MAXN*4];
int R[MAXN*4],L,ln;
void NTT(int *y,int len,int on)
{
for(int i=0;i<len;i++)if(i<R[i])swap(y[i],y[R[i]]);
for(int i=1;i<len;i<<=1)
{
int wn=pow_mod(3,(mod-1)/(i*2));if(on==-1)wn=pow_mod(wn,mod-2);
for(int j=0;j<len;j+=(i<<1))
{
int w=1;
for(int k=0;k<i;k++)
{
LL u=y[j+k],v=1LL*y[j+k+i]*w%mod;
y[j+k]=(u+v)%mod;
y[j+k+i]=(u-v+mod)%mod;
w=1LL*w*wn%mod;
}
}
}
if(on==-1)
{
int temp=pow_mod(len,mod-2);
for(int i=0;i<len;i++)y[i]=1LL*y[i]*temp%mod;
}
}
int pre[MAXM],inv[MAXM];
int C(int n,int m){return 1LL*pre[n]*inv[m]%mod*inv[n-m]%mod;}
int n,m,S,w[MAXN];
void ad(int &x,int y){x+=y;if(x>=mod)x-=mod;}
int main()
{
n=read();m=read();S=read();
int lim=max(n,m);
pre[0]=1;for(int i=1;i<=lim;i++)pre[i]=1LL*pre[i-1]*i%mod;
inv[lim]=pow_mod(pre[lim],mod-2);
for(int i=lim-1;i>=0;i--)inv[i]=1LL*inv[i+1]*(i+1)%mod;
for(int i=0;i<=m;i++)w[i]=read();
for(ln=1;ln<=(m)*2;ln<<=1)L++;
for(int i=0;i<ln;i++)R[i]=(R[i>>1]>>1)|(i&1)<<(L-1);
int u1=1;
for(int i=0;i<=m;i++)
{
if(i*S<=n)
{
int u2=i*S;
A[i]=1LL*C(m,i)*C(n,u2)%mod*pre[u2]%mod*u1%mod*pow_mod(m-i,n-u2)%mod*pre[i]%mod;
u1=1LL*u1*inv[S]%mod;
}
else break;
}
for(int i=0;i<=m;i++)
{
int c1=(i&1)?(-1):(1),c2=inv[i];
B[m-i]=1LL*c1*c2%mod;
}
NTT(A,ln,1);NTT(B,ln,1);
for(int i=0;i<ln;i++)A[i]=1LL*A[i]*B[i]%mod;
NTT(A,ln,-1);
int ans=0;
for(int i=m;i<=2*(m+1)-1;i++)
{
int u=i-m;
int temp=1LL*A[i]*inv[u]%mod;
ad(ans,1LL*temp*w[u]%mod);
}
pr2(ans);
return 0;
}