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;
}
posted @ 2022-02-02 23:57  WWW~~~  阅读(144)  评论(0)    收藏  举报