luogu P4491 [HAOI2018]染色
题面传送门
看成nm同阶然后想了好久
首先这个恰好\(k\)个就很难搞,考虑变成至少\(k\)个然后二项式反演。
设\(f(i)\)为恰好\(i\)个,\(g(i)\)为至少\(i\)个。
\(g\)的话就是钦定\(i*S\)个位置和\(i\)个颜色多重排列剩下的随意。
但是如果直接二项式反演是\(O(m^2)\)的。
看一下式子:\(f(n)=\sum\limits_{i=n}^{m}{(-1)^{i-n}C_n^ig(i)}\)
拆开变成\(n!f(n)=\sum\limits_{i=n}^{m}{(-1)^{i-n}\frac{i!}{(i-n)!}g_i}\)
这个反过来卷积就可以了,时间复杂度\(O(n+mlogm)\)
code:
#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N 300000
#define M 10000000
#define mod 1004535809
#define Mod 998244352
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
using namespace std;
int n,m,k,x,y,z,W[N+5],tr[N+5],S;ll A[N+5],B[N+5],frc[M+5],now,ToT,Inv[M+5];
I ll mpow(ll x,int y=mod-2){ll Ans=1;while(y) y&1&&(Ans=Ans*x%mod),y>>=1,x=x*x%mod;return Ans;}const ll G=3,invG=mpow(G);
I void NTT(ll *A,int n,int Fl){
RI i,j,h;ll key,now,pus;for(i=0;i<n;i++) i<tr[i]&&(swap(A[i],A[tr[i]]),0);for(i=2;i<=n;i<<=1){
for(key=mpow(Fl?G:invG,(mod-1)/i),j=0;j<n;j+=i) for(now=1,h=j;h<j+i/2;h++) pus=now*A[h+i/2]%mod,A[h+i/2]=(A[h]+mod-pus)%mod,A[h]=(A[h]+pus)%mod,now=now*key%mod;
}if(Fl) return;ll Invn=mpow(n);for(i=0;i<n;i++) A[i]=A[i]*Invn%mod;
}
int main(){
freopen("1.in","r",stdin);
RI i;scanf("%d%d%d",&n,&m,&S);for(frc[0]=i=1;i<=max(n,m);i++) frc[i]=frc[i-1]*i%mod;Inv[max(n,m)]=mpow(frc[max(n,m)]);for(i=max(n,m)-1;~i;i--) Inv[i]=Inv[i+1]*(i+1)%mod;
for(k=1;k<=(m<<1);k<<=1);for(i=0;i<k;i++) tr[i]=(tr[i>>1]>>1)|((i&1)?k/2:0);
for(i=0;i<=m&&i*S<=n;i++) A[m-i]=frc[n]*Inv[n-i*S]%mod*mpow(Inv[S],i)%mod*mpow(m-i,n-i*S)%mod*frc[i]%mod*frc[m]%mod*Inv[m-i]%mod*Inv[i]%mod;for(i=0;i<=m;i++)B[i]=(i&1?mod-Inv[i]:Inv[i]);
NTT(A,k,1);NTT(B,k,1);for(i=0;i<k;i++)A[i]=A[i]*B[i]%mod;NTT(A,k,0);
for(i=0;i<=m;i++) scanf("%d",&W[i]),ToT=(W[i]*A[m-i]%mod*Inv[i]+ToT)%mod;printf("%lld\n",ToT);
}