Gym - 102623M(状压dp)
https://codeforces.com/gym/102623/problem/M
#include<cstdio>
#include<bits/stdc++.h>
using namespace std;
#define lbt(x) ((x)&(-x))
typedef long long ll;
int n, m;
char s[33][33];
int stone[33];
int num[1 << 8], zhu[1 << 8];
int dp[33][1 << 8][1 << 8];//dp[row][now][pre]
int route[33][1 << 8][1 << 8];//route[row][now][pre] = prep
//0 not-water
//1 water
int sta[33];
void dfs(int row, int now, int pre) {
if (row < 2) return;
sta[row - 2] = route[row][now][pre];
dfs(row - 1, pre, sta[row - 2]);
}
int main() {
memset(dp, -1, sizeof dp);
scanf("%d %d", &n, &m);
for (int i = 0; i < n; ++i) {
scanf("%s", s[i]); stone[i] = 0;
for (int j = 0; j < m; ++j) stone[i] = (stone[i] << 1) + (s[i][j] == '.' ? 1 : 0);
}
//for (int i = 0; i < n; ++i) printf("%d %d\n", i, stone[i]);
int limit = (1 << m) - 1;
for (int i = 1; i <= limit; ++i) num[i] = num[i - lbt(i)] + 1;
for (int i = 0; i <= limit; ++i) zhu[i] = m - num[i];
if (n == 1) {
int ans = 0, pos = -1;
for (int i = 0; i <= limit; ++i) {
if ((i | stone[0]) > stone[0]) continue;
if (((i | (i << 1) | (i >> 1)) & (limit & stone[0])) < (limit & stone[0])) continue;
if (ans < zhu[i] - zhu[stone[0]]) {
ans = zhu[i] - zhu[stone[0]];
pos = i;
}
}
for (int i = 0; i < m; ++i) {
if (s[0][i] == '#') printf("#");
else if (pos & (1 << m - i - 1)) printf("O");
else printf("X");
}
puts("");
return 0;
}
//for (int i = 0; i <= limit; ++i) printf("%d %d\n", i, zhu[i]);
for (int i = 0; i <= limit; ++i) {
if ((i | stone[0]) > stone[0]) continue;
dp[0][i][0] = zhu[i] - zhu[stone[0]];
}
//for (int i = 0; i <= limit; ++i) printf("%d %d\n", i, dp[0][i][0]); puts("");
for (int i = 0; i <= limit; ++i) {
if ((i | stone[1]) > stone[1]) continue;
//printf("%d\n", i);
for (int pre = 0; pre <= limit; ++pre) {
if ((pre | stone[0]) > stone[0]) continue;
if (((pre | (pre << 1) | (pre >> 1) | i) & (limit & stone[0])) < (limit & stone[0])) continue;
if (n == 2) if (((i | (i << 1) | (i >> 1) | pre) & (limit & stone[n - 1])) < (limit & stone[n - 1])) continue;
if (dp[1][i][pre] < dp[0][pre][0] + zhu[i] - zhu[stone[1]]) {
dp[1][i][pre] = dp[0][pre][0] + zhu[i] - zhu[stone[1]];
}
}
}
//for (int i = 0; i <= limit; ++i) for(int pre = 0; pre <= limit; ++ pre) printf("%d %d\n", i, dp[1][i][pre]);
for (int i = 2; i < n; ++i) {
for (int now = 0; now <= limit; ++now) {
if ((now | stone[i]) > stone[i]) continue;
for (int pre = 0; pre <= limit; ++pre) {
if ((pre | stone[i - 1]) > stone[i - 1]) continue;
for (int prep = 0; prep <= limit; ++prep) {
if ((prep | stone[i - 2]) > stone[i - 2]) continue;
if (((pre | (pre << 1) | (pre >> 1) | prep | now) & (limit & stone[i - 1])) < (limit & stone[i - 1])) continue;
if (i == n - 1) if (((now | (now << 1) | (now >> 1) | pre) & (limit & stone[i])) < (limit & stone[i])) continue;
if (i == 2) if (((prep | (prep << 1) | (prep >> 1) | pre) & (limit & stone[0])) < (limit & stone[0])) continue;
if (dp[i][now][pre] < dp[i - 1][pre][prep] + zhu[now] - zhu[stone[i]]) {
//printf("%d %d %d %d\n", i, now, pre, prep);
dp[i][now][pre] = dp[i - 1][pre][prep] + zhu[now] - zhu[stone[i]];
route[i][now][pre] = prep;
}
}
}
}
}
//for(auto &it : l)
int ans = -1;
int posnow = -1, pospre = -1;
for (int now = 0; now <= limit; ++now) {
if ((now | stone[n - 1]) > stone[n - 1]) continue;
for (int pre = 0; pre <= limit; ++pre) {
if ((pre | stone[n - 2]) > stone[n - 2]) continue;
if (dp[n - 1][now][pre] > ans) {
ans = dp[n - 1][now][pre];
posnow = now, pospre = pre;
}
}
}
//printf("%d\n", ans);
sta[n - 1] = posnow; sta[n - 2] = pospre;
dfs(n - 1, posnow, pospre);
//for (int i = 0; i < n; ++i) printf("%d\n", sta[i]);
for (int i = 0; i < n; ++i) {
int tmp = sta[i];
for (int j = 0; j < m; ++j) {
if (s[i][j] == '#') printf("#");
else if (tmp & (1 << m - j - 1)) printf("O");
else printf("X");
}
puts("");
}
}