AGC 051 D C4 题解
AGC 051 D C4 题解
首先这个图是一个二分图,可以将路径看成一个一个首尾相连的来回。
有以下几种来回:
- 从一个点出发回到自己(4种),数量记为\(a,b,c,d\)
- 从一个点出发到达另一个点,数量记为\(e,f\)。
如果直接解方程的话,就会有\(2\)个自由元,不妨令其为\(e,f\)。
不过把式子列出来,\(a,b,c,d,e,f\)的贡献只和\(e,f,e+f\)有关,所以可以用fft优化。
时间复杂度为\(O(N\log N)\)。
code:
(namespace 里的部分可以看我以前的博客)
using namespace mypoly;
const int MAXN=1e6+5;
vector<int> f1,f2;
int fact[MAXN<<1],ifact[MAXN<<1];
int comb(int A,int B){
return 1ll*fact[A]*ifact[B]%MOD*ifact[A-B]%MOD;
}
int main(){
fact[0]=1;
rb(i,1,2000000) fact[i]=1ll*fact[i-1]*i%MOD;
ifact[2000000]=inv(fact[2000000]);
rl(i,2000000-1,0) ifact[i]=1ll*(i+1)*ifact[i+1]%MOD;
int b,d,c,a;
cin>>b>>d>>c>>a;
f1.resize(min(a,c)+1);
f2.resize(min(b,d)+1);
if((a&1)==(b&1)&&(a&1)==(c&1)&&(a&1)==(d&1));
else{
puts("0");
return 0;
}
rb(e,0,min(a,c)){
if((e&1)==(a&1)){
f1[e]=1ll*ifact[e]*ifact[(a-e)>>1]%MOD*ifact[(c-e)>>1]%MOD;
}
}
rb(f,0,min(b,d)){
if((f&1)==(b&1)){
f2[f]=1ll*ifact[f]*ifact[(b-f)>>1]%MOD*ifact[(d-f)>>1]%MOD;
}
}
f1=f2*f1;
int rest=0;
rep(i,f1.size()){
if(i&1) continue;
int val=f1[i];
val=1ll*val*fact[i]%MOD;
val=1ll*val*fact[(a+b-i)>>1]%MOD;
val=1ll*val*fact[(c+d-i)>>1]%MOD;
int t=i/2+1,r=i/2;
int A=(a+b-i)/2;
int B=(c+d-i)/2;
val=1ll*val*comb(A+t-1,t-1)%MOD;
val=1ll*val*comb(B+r-1,r-1)%MOD;
(rest+=val)%=MOD;
}
printf("%d\n",rest);
return 0;
}