《洛谷P2704 [NOI2001]炮兵阵地》
非常细细细的一题。
首先,这数据量显然是状压。
dp[i][j][k] 表示 到第i行,第i行状态为j,第i - 1行状态未k的最大方案数。
我们从上向下考虑的话,每个放置的棋子会被上面两行棋子的放置状态所影响。
所以我们每次转移的时候需要枚举上面的两行。
这样的话复杂度就是 n * m * m * m。
这显然已经超了(但是正解还就是这样)。
考虑后可以发现,很多状态都是会冲突被删掉的,这样复杂度就少了非常多,所以就够了。
所以我们可以先预处理出冲突的状态。
这里的判断很巧妙,首先把每一行的原图转换成二进制数,去判断山地有没有防炮台。
所以显然我们去把山地转成1,然后就可以位运算判断。
然后对于左右的判断也可以位运算来加速。
空间不够必须用滚动数组。
debug调到裂开。
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 5005; const int M = 1e5 + 5; const LL Mod = 10007; #define pi acos(-1) #define INF 1e9 + 5 #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } } using namespace FASTIO; int n,m,a[105]; int dp[3][1 << 10][1 << 10],num[1 << 10]; bool isvis[105][1 << 10]; int cal(int state) { int num = 0; for(int j = 0;j < m;++j) num += ((state >> j) & 1); return num; } int main() { n = read(),m = read(); for(int i = 0;i < n;++i) { string s;cin >> s; for(int j = 0;j < s.size();++j) a[i] += (s[j] == 'H' ? (1 << j) : 0); } for(int i = 0;i < (1 << m);++i) num[i] = cal(i); for(int i = 0;i < n;++i) for(int j = 0;j < (1 << m);++j) { if((j & a[i]) || (j & (j << 1)) || (j & (j << 2)) || (j & (j >> 1) || (j & (j >> 2)))) isvis[i][j] = 0; else isvis[i][j] = 1; } for(int i = 0;i < (1 << m);++i) { if(!isvis[0][i]) continue; int ma = num[i]; dp[0][i][0] = ma; for(int j = 0;j < (1 << m);++j) { if(!isvis[1][j] || (i & j)) continue; int ta = ma + num[j]; dp[1][j][i] = ta; } } for(int i = 2;i < n;++i)//line { for(int s1 = 0;s1 < (1 << m);++s1) { if(!isvis[i - 2][s1]) continue; for(int s2 = 0;s2 < (1 << m);++s2) { if(!isvis[i - 1][s2] || ((s1 & s2) == 1)) continue; for(int s3 = 0;s3 < (1 << m);++s3) { if(!isvis[i][s3]) continue; if((s1 & s3) || (s2 & s3)) continue; dp[i % 3][s3][s2] = max(dp[i % 3][s3][s2],dp[(i - 1) % 3][s2][s1] + num[s3]); } } } } int ans = 0; for(int i = 0;i < (1 << m);++i) for(int j = 0;j < (1 << m);++j) ans = max(ans,dp[(n - 1) % 3][i][j]); printf("%d\n",ans); system("pause"); return 0; }