HDU-6088 Rikka with Rock-paper-scissors (容斥+MTT)


HDU-6088(容斥+MTT)

考虑计算两个人赢得次数(设为\(a,b\))都是\(d\)的倍数的方案数

注意一下\(a+b>0\)

对于\(a,b\),它的方案数为\(C(n,a)C(n-a,b)\),即\(\frac{n!}{a!b!(n-a-b)!}\)

多以对于每个\(d\)计算一遍所有可行的\(a,b\)能组成的总方案数

这个可以\(MTT\)(因为模数不确定)

\(MTT\)的实现,,在文章下面的扩展介绍里

由于是\(d\)的倍数会包含所有\(d|gcd(a,b)\)的情况,所以还需要容斥一下

复杂度\(n\ln n \log n\),以及极其大的常数

#include
using namespace std;

#define double long double

#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)

template  inline void cmin(T &a,T b){ ((a>b)&&(a=b)); } 
template  inline void cmax(T &a,T b){ ((a>=1,x=x*x%P) if(k&1) res=res*x%P;
	return res;
}
ll qmul(ll x,ll y,ll P){
	y=(y%P+P)%P;
	ll res=0;
	for(;y;y>>=1,x+=x,(x>=P&&(x-=P))) if(y&1) res+=x,(res>=P&&(res-=P));
	return res;
}

int rev[N];
struct Cp{
	double x,y;
	Cp operator + (const Cp t) const { return (Cp){x+t.x,y+t.y}; }
	Cp operator - (const Cp t) const { return (Cp){x-t.x,y-t.y}; }
	Cp operator * (const Cp t) const { return (Cp){x*t.x-y*t.y,x*t.y+y*t.x}; }
}A[N],B[N],w[N];

void FFT(int n,Cp *a,int f){
	rep(i,0,n-1) if(rev[i]>1]>>1)|((i&1)<