神仙题。但是难得的傻孩子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. mysql 分页offset过大性能问题解决思路

    在公司干活一般使用sqlserver数据库.rownumber分页贼好用. 但是晚上下班搞自己的事情就不用sqlserver了.原因就是自己的渣渣1核2g的小服务器完全扛不住sqlserver那么大的 ...

  2. 基于Influxdb对InfluxDBResultMapper的一点扩展

    理想很饱满,现实很骨感. 由于业务需要"灵活可配置"的功能需求,在使用java开发Influxdb查询功能的时候,遇到了一个问题,Measurement注解的名称有可能需要动态变化 ...

  3. java不支持多继承

    java不支持多继承,但支持多重继承,即一个类只能继承一个类,使用extends关键字 一个类可以实现多个接口,接口之间用逗号分隔,使用implements关键字 一个接口可以继承多个其他接口,接口之 ...

  4. 05-03 主成分分析(PCA)

    目录 主成分分析(PCA) 一.维数灾难和降维 二.主成分分析学习目标 三.主成分分析详解 3.1 主成分分析两个条件 3.2 基于最近重构性推导PCA 3.2.1 主成分分析目标函数 3.2.2 主 ...

  5. Chirpy Zippy工具使用心得

    今天在网上看到MVC开发人员必备的工具中有一个工具叫Chirpy Zippy,可以把项目中的js文件自动压缩成min.js文件,于是就试了下这款工具.上到官网:http://chirpy.codepl ...

  6. from..import 语句

    from..import 语句 如果你希望直接将 argv 变量导入你的程序(为了避免每次都要输入 sys.),那么你可以通过使用 from sys import argv 语句来实现这一点. 警告: ...

  7. thinkphp5框架之请求

    又看到请求这一部分,个人认为这部分是算重要的一部分 单独记一篇笔记. 0x01 request请求对象 如果要获取当前的请求信息,可以使用\think\Request类,完全开发手册中也有提到,继承系 ...

  8. 机器学习:数据清洗及工具OpenRefine

    数据分析中,首先要进行数据清洗,才可以继续训练模型,预测等操作. 首先介绍一下什么是数据清洗(定义来自 百度百科,有删减) 数据清洗从名字上也看的出就是把“脏”的“洗掉”,指发现并纠正数据文件中可识别 ...

  9. 《Java并发编程实战》读书笔记-第5章 基础构建模块

    同步容器类 同步容器类实现线程安全的方式:将所有状态封装起来,对每个公有方法使用同步,使得每一次只有一个线程可以访问.同步容器类包含:Vector.Hashtable.Collections.sync ...

  10. 玩转OneNET物联网平台之简介

    授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力.希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石... QQ技术互动交流群:ESP8266&3 ...