ARC 134 F Flipping Coins
ARC 134 F Flipping Coins
很自然想到将排列转变成环,具体的\(i\to p_i\)。
可以发现对于长度=1的环,始终正面朝上。
对于长度≥2的环,不可能全部正面朝上。
考虑哪些操作有作用(操作i时i未被翻转)
令有作用的位置为1,无作用的为0 。
对于一个环,形如'[0111]'[0111]'[01111]...因为两个0不可能相邻。
令每一段的长度为l[i],其中1必须有次序,0必须在第一个1后面,贡献为l[i]-2个向上(可以看作w^l[i] ÷ w^2)。
可以用分治+ntt算出每一种长度的环的系数。(1必须特殊处理)
防止环旋转同构,需要保证第一段的第一个1为环中的最小元素,直接除以环长L即可,记为F[L]。
然后就是合并多个环的方案。
容易发现答案为:
\[[x^n][n!w^n\prod_{i=1}^n(\sum_{j=0}^{\infty} \frac{(x^iF_i)^j}{j!})]=[x^n][n!w^nexp(F)]
\]
然后多项式exp即可。
时间复杂度为\(O(n\log^2n)\)。
Code:
int n,w,ipw2;
vector<int> f;
void trans(int l,int r){
if(l>=r-1) return ;
int mid=(l+r)>>1;
trans(l,mid);
vector<int> F(mid-l+1,0),G(r-l+1,0);
rb(i,2,G.size()-1) G[i]=1ll*(i-1)*ifact[i]%MOD*ipw2%MOD;
rb(i,l,mid) F[i-l]=f[i];
G=F*G;
rb(i,mid+1,r) add(f[i],G[i-l]);
trans(mid+1,r);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
genmath();
cin>>n>>w;
ipw2=inv(1ll*w*w%MOD);
f=vector<int>(n+1,0);
rb(i,2,n) f[i]=1ll*(i-1)*ifact[i-1]%MOD*ipw2%MOD;
f[1]=1;
trans(2,n);
rb(i,1,n) f[i]=1ll*f[i]*inver[i]%MOD;
cout<<1ll*poly_exp(f,n+1)[n]*quick(w,n)%MOD*fact[n]%MOD<<endl;
return 0;
}

浙公网安备 33010602011771号