CF1993E Xor-Grid Problem

结论,异或,状压 DP 2300

Link:https://codeforces.com/problemset/problem/1993/E

先考虑一维的情况。

若只有一维,每次操作的结果和 [AGC016D] XOR Replace 是一样的。对 ai 进行一次操作相当于令 ai:=1inai,再对 j 进行一次操作相当于令 aj:=ai

则题意等价于有一个长度为 n+1 的数列 aan+1=1inai,可以任意交换 aian+1,对于 a1an 求相邻两项差的绝对值之和的最小值。

发现数据范围很小,且贡献仅与相邻元素有关,考虑状压 DP 构造数列,记 fs,i 表示当前填入的数列元素集合为 s,填入的最后一个数是 ai 时美丽值的最小值。初始化 fs,i=,f{i},i=0,则有显然的转移:

1i,jn+1,ij,is,  fs,ifs{j},j+|aiaj|

记全集为 S,答案即为:

min1i,jn+1,ijfS{i},j

总时间复杂度 O(n22n) 级别。

扩展到两维,发现若先进行一次行操作再进行一次列操作,等价于将交点位置修改为整个矩阵的异或和。于是考虑扩展上述做法,题意等价于有一个大小为 (n+1)×(m+1) 的矩阵,第 n+1 行为各列的异或和,第 m+1 列为各行的异或和((n+1,m+1) 即整个矩阵异或和),每次操作可以交换两行/两列,求左上角 n×m 矩阵的美丽值的最小值。

考虑预处理任意两行/两列相邻时的贡献。发现两维的贡献是独立的,不同维的交换并不影响另一维的贡献。发现若枚举了哪一行被放在了 n+1 行上,则对列的贡献的计算就可以直接套用一维的做法了。于是考虑转移时处理 sum(i,j) 表示将第 i 行第 j 列时的最小美丽值,取最小值即可。

在一维做法的基础上仅需再多枚举一维即可,总时间复杂度 O(n2m2n+nm22m)O(n32n) 级别。

复制复制
//
/*
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
*/
posted @   Luckyblock  阅读(32)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示