CF1511E Colorings and Dominoes
阿新 • • 發佈:2021-10-27
最最最好的和最最最痛苦的是一樣的
考慮計數拆開貢獻。
因為在一個方案中一個格子最多隻會貢獻一次,那麼不妨反過來求這個格子貢獻了多少次。
然後發現,行列獨立,那麼我們單獨計算紅藍色,即可。
一個偶數塊貢獻當且僅當前面也是偶數塊。
然後顯然其他不在同一行/同一列的塊就直接隨便亂取就行了。
#include<iostream> #include<cstdio> #include<vector> #define N 300005 #define mod 998244353 #define ll long long int n,m; char a[N]; int sum = 0; std::vector<int>v[N]; int f[N]; inline ll pow(ll a,ll b){ ll ans = 1; while(b){ if(b & 1)ans = ans * a % mod; a = a * a % mod; b >>= 1; } return ans; } ll ans = 0; int main(){ scanf("%d%d",&n,&m); for(int i = 1;i <= n;++i){ scanf("%s",a + 1); for(int j = 1;j <= m;++j) sum += (a[j] == 'o'),v[i].push_back(a[j] == 'o'); } f[2] = f[3] = 1; for(int i = 4;i <= sum;++i) f[i] = (pow(2,i - 3) + f[i - 2]) % mod; for(int i = 2;i <= sum;++i) f[i] = f[i] * pow(2,sum - i) % mod; int now = 0;//當前段長度 for(int i = 1;i <= n;++i,now = 0) for(int j = 0;j < m;++j){ now = now * v[i][j] + v[i][j]; ans = (ans + f[now]) % mod; } now = 0; for(int j = 0;j < m;++j,now = 0) for(int i = 1;i <= n;++i){ now = now * v[i][j] + v[i][j]; ans = (ans + f[now]) % mod; } std::cout<<ans<<std::endl; }