CF1993E Xor-Grid Problem
结论,异或,状压 DP 2300
Link:https://codeforces.com/problemset/problem/1993/E。
先考虑一维的情况。
若只有一维,每次操作的结果和 [AGC016D] XOR Replace 是一样的。对 进行一次操作相当于令 ,再对 进行一次操作相当于令 。
则题意等价于有一个长度为 的数列 ,,可以任意交换 与 ,对于 求相邻两项差的绝对值之和的最小值。
发现数据范围很小,且贡献仅与相邻元素有关,考虑状压 DP 构造数列,记 表示当前填入的数列元素集合为 ,填入的最后一个数是 时美丽值的最小值。初始化 ,则有显然的转移:
记全集为 ,答案即为:
总时间复杂度 级别。
扩展到两维,发现若先进行一次行操作再进行一次列操作,等价于将交点位置修改为整个矩阵的异或和。于是考虑扩展上述做法,题意等价于有一个大小为 的矩阵,第 行为各列的异或和,第 列为各行的异或和( 即整个矩阵异或和),每次操作可以交换两行/两列,求左上角 矩阵的美丽值的最小值。
考虑预处理任意两行/两列相邻时的贡献。发现两维的贡献是独立的,不同维的交换并不影响另一维的贡献。发现若枚举了哪一行被放在了 行上,则对列的贡献的计算就可以直接套用一维的做法了。于是考虑转移时处理 表示将第 行第 列时的最小美丽值,取最小值即可。
在一维做法的基础上仅需再多枚举一维即可,总时间复杂度 级别。
复制复制// /* By:Luckyblock */ #include <bits/stdc++.h> #define LL long long const int kN = 16 + 2; const int kS = (1 << 16) + 10; const LL kInf = 1e18; //============================================================= int n, m, a[kN][kN]; LL ans, all, row[kN][kN], col[kN][kN], f[kS][kN]; LL sum[kN][kN]; //============================================================= void init() { a[n + 1][m + 1] = 0; for (int i = 1; i <= n; ++ i) { a[i][m + 1] = 0; for (int j = 1; j <= m; ++ j) { a[i][m + 1] ^= a[i][j]; a[n + 1][m + 1] ^= a[i][j]; } } for (int j = 1; j <= m; ++ j) { a[n + 1][j] = 0; for (int i = 1; i <= n; ++ i) { a[n + 1][j] ^= a[i][j]; } } for (int i = 1; i <= n + 1; ++ i) { for (int j = 1; j <= n + 1; ++ j) { row[i][j] = 0; for (int k = 1; k <= m + 1; ++ k) row[i][j] += abs(a[i][k] - a[j][k]); } } for (int i = 1; i <= m + 1; ++ i) { for (int j = 1; j <= m + 1; ++ j) { col[i][j] = 0; for (int k = 1; k <= n + 1; ++ k) col[i][j] += abs(a[k][i] - a[k][j]); } } } void DP() { for (int i = 1; i <= n + 1; ++ i) { for (int j = 1; j <= m + 1; ++ j) { sum[i][j] = 0; } } all = (1 << (n + 1)); for (int lst = 1; lst <= m + 1; ++ lst) { for (int s = 1; s < all; ++ s) { for (int i = 1; i <= n + 1; ++ i) { f[s][i] = kInf; } } for (int i = 1; i <= n + 1; ++ i) f[1 << (i - 1)][i] = 0; for (int s = 1; s < all; ++ s) { for (int i = 1; i <= n + 1; ++ i) { if ((s >> (i - 1) & 1) == 0) continue; for (int j = 1; j <= n + 1; ++ j) { if (i == j || (s >> (j - 1) & 1)) continue; f[s | (1 << (j - 1))][j] = std::min(f[s | (1 << (j - 1))][j], f[s][i] + row[i][j] - abs(a[i][lst] - a[j][lst])); } } } for (int i = 1; i <= n + 1; ++ i) { LL minf = kInf; for (int j = 1; j <= n + 1; ++ j) { if (i == j) continue; minf = std::min(minf, f[(all - 1) ^ (1 << (i - 1))][j]); } sum[i][lst] += minf; } } all = (1 << (m + 1)); for (int lst = 1; lst <= n + 1; ++ lst) { for (int s = 1; s < all; ++ s) { for (int i = 1; i <= m + 1; ++ i) { f[s][i] = kInf; } } for (int i = 1; i <= m + 1; ++ i) f[1 << (i - 1)][i] = 0; for (int s = 1; s < all; ++ s) { for (int i = 1; i <= m + 1; ++ i) { if ((s >> (i - 1) & 1) == 0) continue; for (int j = 1; j <= m + 1; ++ j) { if (i == j || (s >> (j - 1) & 1)) continue; f[s | (1 << (j - 1))][j] = std::min(f[s | (1 << (j - 1))][j], f[s][i] + col[i][j] - abs(a[lst][i] - a[lst][j])); } } } for (int i = 1; i <= m + 1; ++ i) { LL minf = kInf; for (int j = 1; j <= m + 1; ++ j) { if (i == j) continue; minf = std::min(minf, f[(all - 1) ^ (1 << (i - 1))][j]); } sum[lst][i] += minf; } } ans = kInf; for (int i = 1; i <= n + 1; ++ i) { for (int j = 1; j <= m + 1; ++ j) { ans = std::min(ans, sum[i][j]); } } } //============================================================= int main() { // freopen("1.txt", "r", stdin); std::ios::sync_with_stdio(0), std::cin.tie(0); int T; std::cin >> T; while (T --) { std::cin >> n >> m; for (int i = 1; i <= n; ++ i) { for (int j = 1; j <= m; ++ j) { std::cin >> a[i][j]; } } init(); DP(); std::cout << ans << "\n"; } return 0; } /* 1 1 2 1 3 */
作者@Luckyblock,转载请声明出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】