题解:AT_abc379_g [ABC379G] Count Grid 3-coloring

题目传送门

前情提要:C 题喜提 6 发罚时,这题没调完了。

发现 min(h,w)14,可以状压。

很经典的套路,发现枚举点 (i,j) 时,只需记下将所有同一行中在 (i,j) 左边的格子和上一行中在 (i1,j) 右边的格子,也就是下图的黄色格子。

可以发现有效状态为 2n 的,但用 3n 也能过,而且更好写,下面是一些卡常技巧:

  • -O3

  • 取模优化。

  • 把常数 const 掉。

  • 可以发现枚举时有一些位是固定为一些数的,只枚举其他位。

具体实现看代码。时间复杂度 O(hw3min(h,w))

Code:

#pragma GCC optimize(3) #include<iostream> #include<cstdlib> #include<ctime> #include<cassert> #include<vector> #include<cmath> #include<cstring> #include<set> #include<climits> #include<queue> #include<stack> #include<bitset> #include<map> #include<algorithm> using namespace std; const int N = 205, MOD = 998244353, pw[] = {1,3,9,27,81,243,729,2187,6561,19683,59049,177147,531441,1594323,4782969}; int h, w, la, f[2][4782969], mp[N][N]; inline int gt(int mask, int k){ return (mask % pw[k]) / pw[k - 1]; } inline void upd(int &x, int y){ ((x += y) >= MOD)? (x -= MOD) : x; } inline void dp(int pos, int x){ int t = x * pw[pos - 1]; if(pos == 1){ int a = (x + 1) % 3, b = (a + 1) % 3; for(int mask = 0; mask < pw[h]; mask += 3){ upd(f[la ^ 1][mask + t], f[la][mask + a]); upd(f[la ^ 1][mask + t], f[la][mask + b]); } } else{ int a = (x + 1) % 3 * pw[pos - 2], b = (x + 2) % 3 * pw[pos - 2]; int aa = 3 * a + a, ab = 3 * a + b, ba = 3 * b + a, bb = 3 * b + b; for(int x = 0; x < pw[h - pos]; x++){ for(int y = 0, z = x * pw[pos]; y < pw[pos - 2]; y++, z++){ upd(f[la ^ 1][z + t + a], f[la][z + aa]); upd(f[la ^ 1][z + t + a], f[la][z + ba]); upd(f[la ^ 1][z + t + b], f[la][z + ab]); upd(f[la ^ 1][z + t + b], f[la][z + bb]); } } } } main(){ // freopen("input.txt", "r", stdin); // freopen("output.txt", "w", stdout); ios::sync_with_stdio(0); cin.tie(0); cin >> h >> w; for(int i = 1; i <= h; i++){ for(int j = 1; j <= w; j++){ char ch; cin >> ch; mp[i][j] = ((ch == '?')? 0 : (ch - '0')); } } if(h > w){ swap(h, w); for(int i = 1; i <= w; i++) for(int j = i + 1; j <= w; j++) swap(mp[i][j], mp[j][i]); } for(int i = 0; i < pw[h]; i++){ f[la][i] = 1; for(int j = 1; j <= h; j++){ if((mp[j][1] && mp[j][1] != gt(i, j) + 1) || (j > 1 && gt(i, j) == gt(i, j - 1))){ f[la][i] = 0; break; } } } for(int i = 2; i <= w; i++){ for(int j = 1; j <= h; j++){ memset(f[la ^ 1], 0, sizeof(f[la ^ 1])); if(mp[j][i]) dp(j, mp[j][i] - 1); else{ dp(j, 0); dp(j, 1); dp(j, 2); } la ^= 1; } } int sum = 0; for(int i = 0; i < pw[h]; i++) upd(sum, f[la][i]); cout << sum << "\n"; }

__EOF__

本文作者louisliang
本文链接https://www.cnblogs.com/louisliang/p/18668258.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   louisliang  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示