Luogu P5339 [TJOI2019]唱、跳、rap和篮球

这看题目一眼容斥,令聊唱、跳、rap和篮球的组数至少\(x\)的方案数为\(g(x)\)

那么显然\(Ans=\sum_{i=0}^{\min(\lfloor \frac{n}{4}\rfloor,a,b,c,d)} (-1)^ig(i)\),考虑如何计算\(g(x)\)

先考虑放下给定的\(x\)组,显然它们的顺序是唯一的,也就是确定了第一个就能确定后面的

相当于现在连续的\(4\)个位置变成了选第一个位置,因此方案数是\(C_{n-3x}^x\)

那么剩下的\(n-4x\)个数怎么办,可重全排列

\[\sum_{i=0}^{a-x}\sum_{j=0}^{b-x}\sum_{p=0}^{c-x}\sum_{q=0}^{d-x} [i+j+p+q=n-4x]\frac{(n-4x)!}{i!j!p!q!} \]

\[=(n-4x)!\times\sum_{i=0}^{a-x}\sum_{j=0}^{b-x}\sum_{p=0}^{c-x}\sum_{q=0}^{d-x}[i+j+p+q=n-4x] \frac{1}{i!}\times \frac{1}{j!}\times \frac{1}{p!}\times \frac{1}{q!} \]

显然后面的部分是一个卷积的形式,由于数据范围小直接暴力卷即可

#include<cstdio>
#include<iostream>
#include<cstring>
#define RI register int
#define CI const int&
#define Ms(f,x) memset(f,x,sizeof(f))
using namespace std;
const int N=1005,mod=998244353;
int n,A,B,C,D,a[N],b[N],c[N],d[N],fact[N],inv[N],len,ret,ans,lim;
inline void inc(int& x,CI y)
{
	if ((x+=y)>=mod) x-=mod;
}
inline void dec(int& x,CI y)
{
	if ((x-=y)<0) x+=mod;
}
inline int quick_pow(int x,int p=mod-2,int mul=1)
{
	for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline void init(CI n)
{
	RI i; for (fact[0]=i=1;i<=n;++i) fact[i]=1LL*fact[i-1]*i%mod;
	for (inv[n]=quick_pow(fact[n]),i=n-1;~i;--i) inv[i]=1LL*inv[i+1]*(i+1)%mod;
}
inline int Comb(CI n,CI m)
{
	return 1LL*fact[n]*inv[m]%mod*inv[n-m]%mod;
}
inline void conv(int *a,int& la,int *b,CI lb,CI n)
{
	RI i,j; static int r[N]; Ms(r,0);
	for (i=0;i<=la;++i) for (j=0;j<=lb;++j)
	if (i+j<=n) inc(r[i+j],1LL*a[i]*b[j]%mod);
	la=min(n,la+lb); for (i=0;i<=la;++i) a[i]=r[i];
}
inline int calc(CI n,CI x)
{
	RI i; Ms(a,0); Ms(b,0); Ms(c,0); Ms(d,0);
	for (i=0;i<=A-x;++i) a[i]=inv[i]; for (i=0;i<=B-x;++i) b[i]=inv[i];
	for (i=0;i<=C-x;++i) c[i]=inv[i]; for (i=0;i<=D-x;++i) d[i]=inv[i];
	len=A-x; conv(a,len,b,B-x,n); conv(a,len,c,C-x,n); conv(a,len,d,D-x,n); return a[n];
}
int main()
{
	scanf("%d%d%d%d%d",&n,&A,&B,&C,&D); init(n);
	RI i; lim=min(n/4,min(min(A,B),min(C,D)));
	for (i=0;i<=lim;++i) ret=1LL*Comb(n-3*i,i)*fact[n-4*i]%mod*calc(n-4*i,i)%mod,
	i&1?(dec(ans,ret),0):(inc(ans,ret),0); return printf("%d",ans),0;
}
posted @ 2020-01-20 11:24  空気力学の詩  阅读(99)  评论(0编辑  收藏  举报