唔,想到了状压之后就不会了……实在是菜

考虑压两行,设$f_{i, j, k}$表示当前到第$i$行,上一行是$j$状态,前一行是$k$状态的最多能放的炮兵的数量。

发现第一维还可以滚掉,好像可以转移了。

但是,这样子$100 * 1024 * 1024 * 1024$时间炸了……怎么办?

考虑先不考虑题目中给出的不能放的格子的贡献,预处理出所有可行解,根据互不侵犯的套路,对于一个状态$i$,在这题中只要满足$i \& (i >> 1)$、$i \& (i >> 2)$、$i \& (i  << 1)$、$i \& (i << 2)$全部都是$0$,那么就是一个合法状态了吧。

对于一个合法状态(记编号为$i$),只要计算出有多少个$1$就相当于可以放多少个炮兵了吧,记这个数量为$num_i$。

一行最多才$10$列,一个炮兵可以打$5$格,发现预处理之后只有$60$来个有效状态了(状态数记为$tot$),$O(ntot^3)$可以承受了。

写一下转移方程:

    $f_{1, i, 0} = num_i$。

    $f_{2, i, j} = max(f_{1, j, 0} + num_i)$  $i, j$不冲突且$i$和第二行的地图不冲突。

    $f_{i, j, k} = max(f_{i - 1, k, t} + num_j)$  $j,k$ 、$k, t$、$j, t$不冲突且$j$和第$i$行的地图不冲突。

答案  $ans = max(f_{n, i, j})$。

注意第二行要分开处理。

时间复杂度$O(ntot^3)$,约为$O(n^4)$。

以后要记得复习!

Code:

#include <cstdio>
#include <cstring>
using namespace std; const int N = ; int n, m, a[N], tot = , b[N], num[N], f[N][N][N]; inline void chkMax(int &x, int y) {
if(y > x) x = y;
} inline int bitCnt(int now) {
int res = ;
for(; now > ; now >>= )
res += (now & );
return res;
} int main() {
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i++) {
char str[];
scanf("%s", str + );
for(int j = ; j <= m; j++)
if(str[j] == 'H') a[i] |= ( << (j - ));
} for(int i = ; i < ( << m); i++)
if(!(i & (i << )) && !(i & (i << )) && !(i & (i >> )) && !(i & (i >> ))) {
++tot;
b[tot] = i, num[tot] = bitCnt(i);
if(!(a[] & b[tot])) f[][tot][] = num[tot];
} for(int i = ; i <= tot; i++)
for(int j = ; j <= tot; j++)
if(!(a[] & b[j]) && !(b[i] & b[j]))
chkMax(f[][j][i], f[][i][] + num[j]); for(int i = ; i <= n; i++)
for(int j = ; j <= tot; j++) {
if(a[i] & b[j]) continue;
for(int k = ; k <= tot; k++) {
if(b[j] & b[k]) continue;
for(int t = ; t <= tot; t++) {
if((b[k] & b[t]) || (b[t] & b[j])) continue;
chkMax(f[i][j][k], f[i - ][k][t] + num[j]);
}
}
} int ans = ;
for(int i = ; i <= tot; i++)
for(int j = ; j <= tot; j++)
chkMax(ans, f[n][i][j]); printf("%d\n", ans);
return ;
}

Luogu 2704 [NOI2001]炮兵阵地的更多相关文章

  1. 洛谷2704 [NOI2001]炮兵阵地

    题目戳这里 Solution 状压DP很好的入门题,用熟练位运算貌似也没那么难. 首先分析一下题目: 看见n=100,m=10,立马就想到了状压,看起来也像DP,所以我们还是采用行号为阶段的状压DP. ...

  2. luogu P2704 [NOI2001]炮兵阵地

    题目描述 司令部的将军们打算在NM的网格地图上部署他们的炮兵部队.一个NM的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P" ...

  3. 状压dp:luogu P2704 [NOI2001]炮兵阵地

    https://www.luogu.org/problemnew/show/P2704 知识点:1.滚动数组:取模实现 2.位运算优先级最低 顾是if(!(a&b))而不是if(!a& ...

  4. [洛谷P2704] [NOI2001]炮兵阵地

    洛谷题目链接:[NOI2001]炮兵阵地 题目描述 司令部的将军们打算在NM的网格地图上部署他们的炮兵部队.一个NM的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示), ...

  5. C++ 洛谷 P2704 [NOI2001]炮兵阵地

    P2704 [NOI2001]炮兵阵地 没学状压DP的看一下 此题意思很简单,如下图,就是十字架上的不能有两个点放炮兵. 在做此题前,先做一下玉米田 玉米田题解 分析: 而m即一行的个数小于等于10, ...

  6. P2704 [NOI2001]炮兵阵地 (状压DP)

    题目: P2704 [NOI2001]炮兵阵地 解析: 和互不侵犯一样 就是多了一格 用\(f[i][j][k]\)表示第i行,上一行状态为\(j\),上上行状态为\(k\)的最多的可以放的炮兵 发现 ...

  7. 洛谷P2704 [NOI2001]炮兵阵地 [状压DP]

    题目传送门 炮兵阵地 题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图 ...

  8. [Poj1185][Noi2001]炮兵阵地(状压dp)

    炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 29476   Accepted: 11411 Descriptio ...

  9. NOI2001 炮兵阵地 洛谷2704

    题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P&quo ...

随机推荐

  1. opencv 学习笔记集锦

    整理了我所了解的有关OpenCV的学习笔记.原理分析.使用例程等相关的博文.排序不分先后,随机整理的.如果有好的资源,也欢迎介绍和分享. 1:OpenCV学习笔记 作者:CSDN数量:55篇博文网址: ...

  2. HTML中id与name的用法

    可以说几乎每个做过Web开发的人都问过,到底元素的ID和Name有什么区别阿?为什么有了ID还要有Name呢? 而同样我们也可以得到最经典的答案:ID就像是一个人的身份证号码,而Name就像是他的名字 ...

  3. EasyWeChat微信开放平台第三方平台接入

    EasyWeChat微信开放平台第三方平台接入 https://www.cnblogs.com/bainiu/p/8022729.html

  4. awk常见基本使用

    -F 指定分割符号 print 外层的引号必须是单引号 $n不能被解析 [root@bogon ~]# .txt a:b:c:d a1:b1:c1:d1 a2:b2:c2:d2 a_: :c:dddd ...

  5. Eclipse 模拟http 请求插件Rest Client

    eclipse update 网址  http://nextinterfaces.com/http4e/install/ 参考 http://www.nextinterfaces.com/eclips ...

  6. Mongodb3.0 新增用户身份验证db.createUser()

    定义:创建一个数据库新用户用db.createUser()方法,如果用户存在则返回一个用户重复错误. 语法:db.createUser(user, writeConcern)    user这个文档创 ...

  7. DFT的理解

    在以前学习的离散傅立叶变换(DFT),总是不能理解只是知道公式 X(k) = Σx(n) * WNnk    ,也不知道如何得来的. 现在可以聊聊了,因为最近在使用MATLAB实际的操作了所以比以前了 ...

  8. 字符串,字符数组(C/C++)

    这个地方困惑我好久了,废话不多说 char c1[]="12345"; char *c2="12345"; string c3="12345" ...

  9. java - 只输出不含中文标点符号的中文

    String a ="12dss显示,‘:()中文只"; StringBuffer b = new StringBuffer(); for(int i = 0;i<a.len ...

  10. 用Python语言设计GUI界面

    我们大家都编写过程序,但是如果能够设计一个GUI界面,会使程序增添一个很大的亮点!今天就让我们来用目前十分流行的python语言写出一个最基本的GUI,为日后设计更加漂亮的GUI打下基础. 工具/原料 ...