(updateeee 忘了最后要减去了,,直接把错误答案的公式留在了这里2019.10.13)
ldx说我容斥做少了,我觉得说的真tm对,来做做容斥。
首先考虑正难则反。如果没有ctrl不好算,我们算有的。
如果有i个ctrl,将这4个人缩成一个点,加上其他人有n-3i个点。从中随便找i个都可以作为ctrl。
所以首先,i个ctrl的方案有
但是注意,其它空位放的人也可能有ctrl。
所以我们改i的意义为至少有i对ctrl。
接着发现在算i=1的时候,i=2要算2遍,3三遍,i=2的时候,3算3遍,4算6遍。
大概是这个意思
XX。。。。
X。。。。
。X。。。。
2遍。
XXX。。。。
X。。。。
。X。。。
。。X。。。
如此,任何一种更大的j的方式,都会被小的i给算个很多遍。
也就是说算i的时候,j要算遍。
所以我们要构造一个容斥式子使得所有算了j这个方案的系数合起来是1。
有一个很tm巧妙的式子是
考虑(1+(-1))^n的符号
+-+-+-+-,,,
因为式子中-1的次方是i-1,所以变成了
-+-+-+-+,,,
又没算第一项。也就是说少算了第一个-1,那答案就是1。
运用这种跟组合有关的前缀式子,令G(i)表示i个位子随便乱弄的方案,我们可以将答案表示成
所以我们要处理G。因为在乱弄的时候要考虑相同的东西放不同位置答案是一样的,而且东西的数量还有限制。
如果现在还能使用的人数少于n-4i,那贡献肯定是0.放都放不完。如果n<0了,没地方放也是一样。
当剩下的大于等于n-4i时
为什么呢,剩下的位子随便放是前面的阶乘。但同样的东西交换不算答案,所以还要消去同样东西的顺序。并且还要符合数量合。
反正只要一个位子的答案,直接卷积就是了。
所以我们得到的非法方案总共为
然后用总数一减得到的式子应该是
也就是前面添加了i=0项,然后-1符号反一下。
以上。
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;
ch=getchar();
}return cnt*f;
}const int mod=998244353;
int limit,l,r[1000003],a[1000003],b[1000003],c[1000003],d[1000003];
int ksm(int a,int b){
int sum=1;
while(b){
if(b&1)sum=sum*a%mod;a=a*a%mod;b>>=1;
}return sum;
}
void getl(int len){
limit=1,l=0;
while(limit<=len)limit<<=1,l++;
for(int i=0;i<limit;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
}
void NTT(int *a,int len,int inv){
for(int i=0;i<len;i++)if(i<r[i])swap(a[i],a[r[i]]);
for(int mid=1;mid<len;mid<<=1){
int wn=ksm(3,(mod-1)/(mid<<1));
for(int i=0;i<len;i+=mid*2){
int omega=1;
for(int j=0;j<mid;j++,omega=omega*wn%mod){
int x=a[i+j],y=a[i+j+mid]*omega%mod;
a[i+j]=(x+y)%mod;a[i+j+mid]=(x-y+mod)%mod;
}
}
}if(inv==1)return;
reverse(a+1,a+len);int gu=ksm(len,mod-2);
for(int i=0;i<len;i++)a[i]=a[i]*gu%mod;
}
int fac[1000003],ifac[1000003];
int Q(int N,int A,int B,int C,int D){
if(N>A+B+C+D)return 0;
if(N<0)return 0;
getl((A+B+C+D)<<1);
for(int i=0;i<limit;i++)a[i]=(i<=A)?ifac[i]:0;
for(int i=0;i<limit;i++)b[i]=(i<=B)?ifac[i]:0;
for(int i=0;i<limit;i++)c[i]=(i<=C)?ifac[i]:0;
for(int i=0;i<limit;i++)d[i]=(i<=D)?ifac[i]:0;
NTT(a,limit,1);NTT(b,limit,1);NTT(c,limit,1);NTT(d,limit,1);
for(int i=0;i<limit;i++)a[i]=a[i]*b[i]%mod*c[i]%mod*d[i]%mod;
NTT(a,limit,-1);return fac[N]*a[N]%mod;
}int cc[2003][2003];int n,A,B,C,D;
signed main(){fac[0]=ifac[0]=1;
n=in;A=in;B=in;C=in;D=in;for(int i=0;i<=2000;i++)cc[i][0]=1;
for(int i=1;i<=2000;i++)for(int j=1;j<=2000;j++)cc[i][j]=(cc[i-1][j]+cc[i-1][j-1])%mod;
int minn=0x3f3f3f3f;minn=min(n/4,min(A,min(B,min(C,D))));
for(int i=1;i<=1000000;i++)fac[i]=fac[i-1]*i%mod;
ifac[1000000]=ksm(fac[1000000],mod-2);
for(int i=999999;i>=1;i--)ifac[i]=ifac[i+1]*(i+1)%mod;
int ans=0;
for(int i=0,_1=1;i<=minn;i++){
ans=(ans+_1*cc[n-i*3][i]%mod*Q(n-4*i,A-i,B-i,C-i,D-i)%mod)%mod;
_1=_1*(mod-1)%mod;
}
//cout<<cc[n-3][1]<<" "<<Q(n-4,A-1,B-1,C-1,D-1)<<endl;
cout<<ans;
return 0;
}