神仙题。但是难得的傻孩子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. JavaSE----03.数据类型

    03.数据类型 1.数据类型分类     Java是强类型语言,Java中的数据类型分为两大类,分别是基本数据类型和引用数据类型.其中,基本数据类型由Java语言定义,其数据占用内存的大小固定,在内存 ...

  2. JPG和PNG特性分析及适用范围

    个人博客: http://mcchen.club JPG的特性   ----有损压缩 1.支持摄影图像或写实图像的高级压缩,并且可利用压缩比例控制图像文件大小. 2.有损压缩会使图像数据质量下降,并且 ...

  3. 对BUG的分析与理解

    对BUG的分析与理解 bug的分类 bug,其实就是软件期望的行为与实际行为的差异.从程序的角度来看,在软件整个生命周期中都会有bug的出现.需求分析过程中,需求理解的不足,导致的理解错位 ,遗漏甚至 ...

  4. Spring Security 学习记录

    一.核心拦截器详细说明 1.WebAsyncManagerIntegrationFilter 根据请求封装获取WebAsyncManager 从WebAsyncManager获取/注册Security ...

  5. Vue入门教程 第一篇 (概念及初始化)

    注:为了本教程的准确性,部分描述引用了官网及网络内容. 安装Vue 1.使用npm安装vue: npm install vue 2.下载使用js文件: https://vuejs.org/js/vue ...

  6. 在我的新书里,尝试着用股票案例讲述Python爬虫大数据可视化等知识

    我的新书,<基于股票大数据分析的Python入门实战>,预计将于2019年底在清华出版社出版. 如果大家对大数据分析有兴趣,又想学习Python,这本书是一本不错的选择.从知识体系上来看, ...

  7. 带你涨姿势的认识一下 Kafka

    Kafka 基本概述 什么是 Kafka Kafka 是一个分布式流式平台,它有三个关键能力 订阅发布记录流,它类似于企业中的消息队列 或 企业消息传递系统 以容错的方式存储记录流 实时记录流 Kaf ...

  8. 想转行做程序员,是学习JAVA还是Python?哪个更好?

    请大家务必审题,转行做程序员,是程序员,并非数据分析也不是软件测试. 首先声明:这是一篇容易引起撕逼的问答,为了祖国和谐,人民安康,请各位看官尽量理性讨论. 同时,这篇文章是面向一些初入行的朋友进行一 ...

  9. Nmon监控结果分析

    一:CPU信息 SYS_SUMM图表: 1.折线图中蓝线为cpu占有率变化情况:粉线为磁盘IO的变化情况: 2.下面表各种左边的位磁盘的总体数据,包括如下几个: Avg tps during an i ...

  10. 服务器端 SOCKET 编程

    使用 Socket 的程序在使用 Socket 之前必须调用 WSAStartup() 函数, 此函数在应用程序中用来初始化 Windows Socket DLL, 只有此函数调用成功后,应用程序才可 ...