神仙题。但是难得的傻孩子cbx没有喊题解,所以也就难得的自己想出来了一个如此神仙的题。

如果是自己想的,说它神仙是不是有点不合适啊。。?

反正的确不好像。关键就在于这个标签。颓完标签就差不多会了。

%%%cbx那么快就想出来了。(2个小时?)

废话多了。

先考虑暴力。对于16的数据范围当然要考虑状压,状态表示每一个位置是否要放兵。

我们只需要考虑左边对右边,上边对下边的贡献,最后把答案×2即可。

然后枚举每一层的状态,逐层转移即可。

复杂度是$O((2^{C})^2 \times C \times R)$,9e12左右

我想到一个没什么用的优化,既然你已经知道了本层的士兵数量,那么那些状态里不合法的就不用枚举了。

预处理一下,复杂度是$O((C_C^{C/2})^2 \times C \times R)$,极端情况3e11左右

但是不要想了,一分也不会多的。

 #include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
using namespace std;
int r,c,num[],dp[][],re[][],loc[][],scnt[],ANS;
char s[][];
vector<int>v[];
int cal(int ro,int lst,int tst){
int ans=;
for(int i=;i<scnt[tst];++i)if(loc[tst][i]+==loc[tst][i+]&&s[ro][i]==s[ro][i+])ans++;
for(int i=;i<=c;++i)if(lst&<<i-&&tst&<<i-&&s[ro-][re[lst][i]]==s[ro][re[tst][i]])ans++;
return ans;
}
int main(){
scanf("%d%d",&r,&c);
for(int i=;i<=r;++i)scanf("%s",s[i]+),num[i]=strlen(s[i]+);
for(int i=;i<<<c;++i){
int cnt=,j=i,alm=;
while(j)j^=j&-j,cnt++;
scnt[i]=cnt;
v[cnt].push_back(i);
for(int k=;k<=c;++k)re[i][k]=re[i][k-]+(i&<<k-?:);
for(int k=;k<=c;++k)if(i&<<k-)loc[i][++alm]=k;
}//printf("%d\n",v[1][0]);
for(int i=;i<=r;++i){
memset(dp[i&],,sizeof dp[i&]);
for(int j=;j<v[num[i-]].size();++j)for(int k=;k<v[num[i]].size();++k)
dp[i&][v[num[i]][k]]=max(dp[i&][v[num[i]][k]],dp[i&^][v[num[i-]][j]]+cal(i,v[num[i-]][j],v[num[i]][k]));
}
for(int i=;i<=v[num[r]].size();++i)ANS=max(ANS,dp[r&][v[num[r]][i]]);
printf("%d\n",ANS<<);//printf("%d\n",cal(2,1,1));
}

用作对拍的T40

复杂度的瓶颈明显就在于$C_{16}^8$或者$2^{16}$的平方上,状压肯定是少不了的但是平方不能有。

也就是必须一次只枚举一个状态进行转移。

找这题的特殊性质,如果依次考虑每个格子,那么dp值是否增加只与左边一位和上边的一位有关。

所以你枚举上面的一整层是多余的。

我们只要知道这一位自身,左边和上面是谁就好了,其余位置并不在意。

而这一位填完之后,上面的那一位就作废了,取而代之的是这一位。。。

所以我们的状态表示的就是当前轮廓线上的每一位有没有放数。。。

具体实现还是比较简单的。需要修改二进制下的某一位,判断二进制下某一位左右各有几个1(知道是第几个就可以判断它到底是谁了)

一个打成函数,一个预处理。

复杂度$O(2^C \times C \times R)$

注意干掉不合法的状态(一行完毕之后发现它填数的个数不够或者是多了)

 #include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
char s[][];int n,m,dp[][],cntl[][],cntr[][],ans,l[];
int chg(int st,int p,int w){
if(!p)return st>><<|w;
int r=st&(<<p)-;
st>>=p+;st<<=;st|=w;st<<=p;//printf("%d\n",st);
return st|r;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i)scanf("%s",s[i]+),l[i]=strlen(s[i]+);
for(int i=;i<<<m;++i){
for(int j=;j<=m+;++j)cntl[i][j]=cntl[i][j-]+(i&<<j-?:);
for(int j=m-;j;--j)cntr[i][j]=cntr[i][j+]+(i&<<j?:);
// for(int j=1;j<=m;++j)printf("%d %d %d %d\n",i,j,cntl[i][j],cntr[i][j]);
}//return 0;
int nw=,ls=;memset(dp[nw],0xa0,sizeof dp[nw]);dp[nw][]=;
for(int i=;i<=n;++i){
for(int j=;j<=m;++j){
nw^=;ls^=;memset(dp[nw],0xa0,sizeof dp[nw]);
for(int st=;st<<<m;++st){
char sl=s[i][cntl[st][j]],su=s[i-][l[i-]-cntr[st][j]],sT=s[i][cntl[st][j]+];//printf("%d %d %d %c %c %c\n",i,j,st,sT,sl,su);
if(!(st&<<j-))sl=;if(!(st&<<j-))su=;
if(sT)dp[nw][chg(st,j-,)]=max(dp[nw][chg(st,j-,)],dp[ls][st]+(sl==sT)+(sT==su));
dp[nw][chg(st,j-,)]=max(dp[nw][chg(st,j-,)],dp[ls][st]);
}
// for(int s=0;s<1<<m;++s)printf("%d %d %d %d\n",i,j,s,dp[nw][s]);
}
for(int st=;st<<<m;++st)if(cntl[st][m+]!=l[i])dp[nw][st]=0xa0a0a0a0;
// int j=m;for(int s=0;s<1<<m;++s)printf("%d %d %d %d\n",i,j,s,dp[nw][s]);
}
for(int i=;i<<<m;++i)ans=max(ans,dp[nw][i]);
printf("%d\n",ans*);//printf("%d\n",chg(1,3,1));
}

没有cbx说的那么好写好调。

他给出的小的容易出锅的样例:

2 1 A A

2 2 A A

3 3 AB AA BA(这个是我出锅的)

group:状压dp,轮廓线的更多相关文章

  1. [杂题]:group(状压DP+轮廓线)

    题目描述 $pure$在玩一个战略类游戏.现在有一个士兵方阵,每行有若干士兵,每个士兵属于某个兵种.行的顺序不可改变,且每一行中士兵的顺序也不可改变.但由于每一行都有$C$个位置($C$不小于任一行的 ...

  2. group 状压dp

    应某些人要求,我把标签删掉了 这是一道好题. 一看$c<=16$果断状压,但是怎么压? 一个很显然的思路是,枚举上下两层的状态,每一层的状态极限有$C(c,c/2)$,c=16的时候有13000 ...

  3. POJ 3254 Corn Fields (状压DP,轮廓线DP)

    题意: 有一个n*m的矩阵(0<n,m<=12),有部分的格子可种草,有部分不可种,问有多少种不同的种草方案(完全不种也可以算1种,对答案取模后输出)? 思路: 明显的状压DP啦,只是怎样 ...

  4. poj2411 Mondriaan's Dream (轮廓线dp、状压dp)

    Mondriaan's Dream Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 17203   Accepted: 991 ...

  5. hdu5304 Eastest Magical Day Seep Group&#39;s Summer 状压dp+生成树

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5304 16个点的无向图,问能生成多少个n条边的连通图.(即多一条边的树) 先n^3 * 2^n 枚举全部的 ...

  6. 多米诺骨牌放置问题(状压DP)

    例题: 最近小A遇到了一个很有趣的问题: 现在有一个\(n\times m\)规格的桌面,我们希望用\(1 \times 2\)规格的多米诺骨牌将其覆盖. 例如,对于一个\(10 \times 11\ ...

  7. bzoj 1087 状压dp

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4130  Solved: 2390[Submit][ ...

  8. dp,状压dp等 一些总结

    也就作业几题而已,分析一下提醒 最重要的就是,记住,没用的状态无论怎么转移最后都会是没用的状态,所以每次转移以后的有值的状态都是有用的状态. 几种思考方向: 第一种:枚举当前的状态,转移成另外一个状态 ...

  9. 牛客比赛-状压dp

    链接:https://www.nowcoder.com/acm/contest/74/F来源:牛客网 德玛西亚是一个实力雄厚.奉公守法的国家,有着功勋卓著的光荣军史. 这里非常重视正义.荣耀.职责的意 ...

随机推荐

  1. svg foreignObject的作用(文本换行,生成图片)

    SVG内部利用foreignObject嵌入XHTML元素 <foreignObject>元素的作用是可以在其中使用具有其它XML命名空间的XML元素,换句话说借助<foreignO ...

  2. (转) websocket 和 socket 剖析

    Socket 与 WebSocket 本站文章除注明转载外,均为本站原创或者翻译. 本站文章欢迎各种形式的转载,但请18岁以上的转载者注明文章出处,尊重我的劳动,也尊重你的智商: 本站部分原创和翻译文 ...

  3. java的动手动脑10月20日

    (1)动手动脑 该函数没有赋初值再就是如果类提供一个自定义的构造方法,将导致系统不在提供默认的构造方法. (2) public class test { /*** @param args*/publi ...

  4. 新手入门HTML5开发,你必须先搞懂这6个问题

    凭借着跨平台,实时更新,无需安装,易于分发等众多优点,HTML5受到越来越多企业的青睐.而凭借着入门相对简单的优势,很多人编程初学者都选择学习HTML5.但对于初学者来说,学习HTML5之前,会有很多 ...

  5. .NET Core3.0创建Worker Services

    .NET CORE 3.0新增了Worker Services的新项目模板,可以编写长时间运行的后台服务,并且能轻松的部署成windows服务或linux守护程序.如果安装的vs2019是中文版本,W ...

  6. 怎样快速找到某一行代码的git提交记录

    利用notepad++提高问题分析效率,以及快速找到某一行代码的git提交记录 1. 全目录搜索/替换 Notepad++是一款强大的文本编辑工具,当知道大概的关键词但不知道在哪个日志时可以使用not ...

  7. C语言1作业004

    这个作业属于哪个课程 C语言作业004 我在这个课程的目标是 理解和掌握for语句的基本操作 这个作业在哪个具体方面帮助我实现目标 循环结构的应用,数学函数基本问题 参考文献 C语言程序设计(第3版) ...

  8. Python爬取散文网散文

    配置python 2.7 bs4 requests 安装 用pip进行安装 sudo pip install bs4 sudo pip install requests 简要说明一下bs4的使用因为是 ...

  9. Arduino学习笔记④ 经典按键实验

    1.前言     我们讲了数字IO口介绍以及做了流水灯演示(主要用到IO口的输出功能),这节课我们讲解一下IO口的输入功能,说到输入功能,最经典的例子莫过于按键实验.废话少说,赶紧上车. 2.实验材料 ...

  10. Java基础(二十七)Java IO(4)字符流(Character Stream)

    字符流用于处理字符数据的读取和写入,它以字符为单位. 一.Reader类与Writer类 1.Reader类是所有字符输入流的父类,它定义了操作字符输入流的各种方法. 2.Writer类是所有字符输出 ...