[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})$,可以通过
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }