[atARC136F]Flip Cells

说明

记$N=HW$,时间复杂度均用$N$描述

定义$o_{n}$表示(结束状态下)操作$n$次后状态不变的概率

定义$g_{n}$表示(初始状态下)操作$n$次恰成为结束状态的概率

定义$f_{n}$表示(初始状态下)操作$n$次后恰首次成为结束状态的概率

记$O(x),G(x)$和$F(x)$为(上述三个序列)所对应的生成函数

记$O_{exp(x)},G_{exp}(x)$和$F_{exp}(x)$为(上述三个序列)所对应的指数生成函数

记$\begin{cases}E_{0}(x)=\sum_{n\equiv 0(mod\ 2)}\frac{(\frac{x}{N})^{n}}{n!}=\frac{e^{\frac{x}{N}}+e^{-\frac{x}{N}}}{2}\\E_{1}(x)=\sum_{n\equiv 1(mod\ 2)}\frac{(\frac{x}{N})^{n}}{n!}=\frac{e^{\frac{x}{N}}-e^{-\frac{x}{N}}}{2}\end{cases}$(操作偶/奇数次的指数生成函数)

计算

枚举实际操作次数,转移即$f_{n}=g_{n}-\sum_{i=0}^{n-1}o_{n-i}f_{i}$,代入生成函数可得$F(x)=\frac{G(x)}{O(x)}$

考虑答案,即$ans=\sum_{n\ge 0}n\cdot f_{n}=F'(1)=\frac{O(1)G'(1)-O'(1)G(1)}{O^{2}(1)}$,问题即求$O(x)$和$G(x)$

定义$o'_{n}$和$g'_{n}$表示在$o_{n}$和$g_{n}$的基础上强制操作位置不同的方案数,两者均可简单dp求出

(以下以$O(x)$为例)枚举实际翻转位置数,即$O_{exp}(x)=\sum_{n=0}^{N}o'_{n}E_{1}^{n}(x)E_{0}^{N-n}(x)$

代入并展开,即形如$O_{exp}(x)=\sum_{|n|\le N}a_{n}e^{\frac{n}{N}}$,进而$O(x)=\sum_{|n|\le N}\frac{a_{n}}{1-\frac{n}{N}x}$

关于展开,注意到$a_{2i-N}=[x^{i}]\sum_{n=0}^{N}\frac{o'_{n}}{2^{N}}(x-1)^{n}(x+1)^{N-n}$,以$x+1$为主元处理即可

得到$O(x)$和$G(x)$后,直接求导并计算会有分母为0的情况,将$O(x)$和$G(x)$均乘上$1-x$即可

具体的,此时$O(1)$中$n=N$时$1-x$抵消(其余项均为0)$,O'(1)$中$n=N$时分子也为0

时间复杂度为$o(N^{2})$,可以通过

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 2505
 4 #define M 55
 5 #define mod 998244353
 6 #define ll long long
 7 int n,H,W,ans,mi[N],C[N][N],a[M],b[M],c[M],o[N],h[N],g[N],f[N];
 8 char s[M];
 9 int qpow(int n,int m=mod-2){
10     int s=n,ans=1;
11     while (m){
12         if (m&1)ans=(ll)ans*s%mod;
13         s=(ll)s*s%mod,m>>=1;
14     }
15     return ans;
16 }
17 void get(int *a,int *b,int *g){
18     g[0]=1;
19     for(int i=1;i<=H;i++){
20         memset(c,0,sizeof(c));
21         for(int j=0;j<=a[i];j++){
22             int jj=b[i]-(a[i]-j);
23             if ((0<=jj)&&(jj<=W-a[i]))c[j+jj]=(ll)C[a[i]][j]*C[W-a[i]][jj]%mod;
24         }
25         memcpy(h,g,sizeof(h));
26         memset(g,0,sizeof(h));
27         for(int j=0;j<=W;j++)
28             for(int k=j;k<=n;k++)g[k]=(g[k]+(ll)c[j]*h[k-j])%mod;
29     }
30 }
31 void calc(int *a){
32     memset(h,0,sizeof(h));
33     for(int i=0;i<=n;i++)
34         for(int j=0;j<=i;j++){
35             int s=(ll)a[i]*C[i][j]%mod*mi[j]%mod;
36             if (j&1)s=mod-s;
37             h[n-j]=(h[n-j]+s)%mod;
38         }
39     memset(f,0,sizeof(f));
40     for(int i=0;i<=n;i++)
41         for(int j=0;j<=i;j++)f[j]=(f[j]+(ll)h[i]*C[i][j])%mod;
42     int inv=qpow(mi[n]);
43     for(int i=0;i<=n;i++)a[i]=(ll)f[i]*inv%mod;
44 }
45 int main(){
46     mi[0]=1;
47     for(int i=1;i<N;i++)mi[i]=(mi[i-1]<<1)%mod;
48     for(int i=0;i<N;i++){
49         C[i][0]=C[i][i]=1;
50         for(int j=1;j<i;j++)C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
51     }
52     scanf("%d%d",&H,&W),n=H*W;
53     for(int i=1;i<=H;i++){
54         scanf("%s",s+1);
55         for(int j=1;j<=W;j++)
56             if (s[j]=='1')a[i]++;
57     }
58     for(int i=1;i<=H;i++)scanf("%d",&b[i]);
59     get(b,b,o),get(a,b,g),calc(o),calc(g);
60     int O1=o[n],G1=g[n],O2=0,G2=0;
61     for(int i=0;i<n;i++){
62         int inv=qpow(((ll)((i<<1)-n+mod)*qpow(n)-1+mod)%mod);
63         O2=(O2+(ll)o[i]*inv)%mod,G2=(G2+(ll)g[i]*inv)%mod;
64     }
65     ans=((ll)O1*G2-(ll)O2*G1%mod+mod)%mod*qpow(O1,mod-3)%mod;
66     printf("%d\n",ans);
67     return 0;
68 } 
View Code

 

posted @ 2022-03-11 10:48  PYWBKTDA  阅读(77)  评论(0编辑  收藏  举报