【loj2504】小H爱染色(组合,多项式)
记 \(H_i\) 表示给 \(i\) 个球染色,染两次,每次染 \(m\) 个,其中要求第一个球必须染。那么题目即求:
\[\sum_{i=0}^{n-1}H(n-i)F(i)
\]
\(n\) 很大不好求,有种比较神仙的做法。
设 \(F(i)=\sum_{j=0}^mf_ji^j\),对每个 \(j\) 分别求解:
\[\sum_{j=0}^mf_j\sum_{i=0}^{n-1}H(n-i)i^j
\]
考察 \(i^j\) 的组合意义:对 \(i\) 个不同的球染 \(j\) 次色每次染一个的方案数。
刚好我们需要对后面的 \(n-i\) 个球染两次色每次染 \(m\) 个。
那么可以考虑直接枚举前面部分染 \(j\) 次共染的球数 \(t\),后面部分共染的球数 \(k\),这样就不需要枚举 \(i\) 了,因为 \(i\) 就是后面 \(k\) 个球的第一个。
后面部分的方案数很容易计算,为 \(\binom{k}{m}\binom{m}{2m-k}\)。
前面部分相当于要求对 \(t\) 个球染 \(j\) 次色,其中所有球都被染到的方案数。容斥可以得到 \(\sum_{i=0}^t\binom{t}{i}(-1)^i(t-i)^j\)。
于是答案为:
\[\begin{aligned}
&\sum_{j=0}^mf_j\sum_{t=0}^m\sum_{k=m}^{2m}\binom{n}{t+k}\binom{k}{m}\binom{m}{2m-k}\sum_{i=0}^t\binom{t}{i}(-1)^i(t-i)^j\\
=&\sum_{t=0}^m\sum_{k=m}^{2m}\binom{n}{t+k}\binom{k}{m}\binom{m}{2m-k}\sum_{i=0}^t\binom{t}{i}(-1)^iF(t-i)
\end{aligned}
\]
其中 \(\sum\limits_{i=0}^t\binom{t}{i}(-1)^iF(t-i)\) 可以先卷积求出,接着再和只跟 \(k\) 有关的 \(\binom{k}{m}\binom{m}{2m-k}\) 卷起来就能得到 \(t+k=i\) 时的答案,再乘上 \(\binom{n}{t+k}\) 相加即可。
#include<bits/stdc++.h>
#define LN 22
#define N 1000010
using namespace std;
namespace modular
{
const int mod=998244353;
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 1ll*x*y%mod;}
}using namespace modular;
inline int poww(int a,int b)
{
int ans=1;
while(b)
{
if(b&1) ans=mul(ans,a);
a=mul(a,a);
b>>=1;
}
return ans;
}
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
return x*f;
}
int n,m,fac[N*3],ifac[N*3];
int f[N<<2],g[N<<2];
int rev[N<<2];
vector<int>w[LN][2];
int C(int n,int m)
{
if(n<0||m<0||m>n) return 0;
return mul(fac[n],mul(ifac[m],ifac[n-m]));
}
void init(int limit)
{
for(int bit=0,mid=1;mid<limit;bit++,mid<<=1)
{
int len=mid<<1;
int gn=poww(3,(mod-1)/len);
int ign=poww(gn,mod-2);
int g=1,ig=1;
for(int j=0;j<mid;j++,g=mul(g,gn),ig=mul(ig,ign))
w[bit][0].push_back(g),w[bit][1].push_back(ig);
}
}
void NTT(int *a,int limit,int opt)
{
opt=(opt<0);
for(int i=0;i<limit;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)*(limit>>1));
for(int i=0;i<limit;i++)
if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int bit=0,mid=1;mid<limit;bit++,mid<<=1)
{
for(int i=0,len=mid<<1;i<limit;i+=len)
{
for(int j=0;j<mid;j++)
{
int x=a[i+j],y=mul(w[bit][opt][j],a[i+mid+j]);
a[i+j]=add(x,y),a[i+mid+j]=dec(x,y);
}
}
}
if(opt)
{
int tmp=poww(limit,mod-2);
for(int i=0;i<limit;i++)
a[i]=mul(a[i],tmp);
}
}
int main()
{
n=read(),m=read();
fac[0]=1;
for(int i=1;i<=m*3;i++) fac[i]=mul(fac[i-1],i);
ifac[m*3]=poww(fac[m*3],mod-2);
for(int i=m*3;i>=1;i--) ifac[i-1]=mul(ifac[i],i);
int limit=1;
while(limit<=(m<<1)) limit<<=1;
init(limit);
for(int i=0;i<=m;i++) f[i]=mul(ifac[i],read());
for(int i=0;i<=m;i++) g[i]=mul(ifac[i],(i&1)?mod-1:1);
NTT(f,limit,1),NTT(g,limit,1);
for(int i=0;i<limit;i++) f[i]=mul(f[i],g[i]);
NTT(f,limit,-1);
for(int i=0;i<=m;i++) f[i]=mul(f[i],fac[i]);
for(int i=m+1;i<limit;i++) f[i]=0;
for(int i=0;i<limit;i++) g[i]=0;
for(int i=m;i<=(m<<1);i++) g[i-m]=mul(C(i,m),C(m,(m<<1)-i));
NTT(f,limit,1),NTT(g,limit,1);
for(int i=0;i<limit;i++) f[i]=mul(f[i],g[i]);
NTT(f,limit,-1);
int binom=1;
for(int i=0;i<m;i++) binom=mul(binom,dec(n,i));
binom=mul(binom,ifac[m]);
int ans=0;
for(int i=m;i<=m*3;i++)
{
ans=add(ans,mul(binom,f[i-m]));
binom=mul(binom,dec(n,i));
binom=mul(binom,mul(ifac[i+1],fac[i]));
}
printf("%d\n",ans);
return 0;
}

浙公网安备 33010602011771号