group:状压dp,轮廓线
神仙题。但是难得的傻孩子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,轮廓线的更多相关文章
- [杂题]:group(状压DP+轮廓线)
题目描述 $pure$在玩一个战略类游戏.现在有一个士兵方阵,每行有若干士兵,每个士兵属于某个兵种.行的顺序不可改变,且每一行中士兵的顺序也不可改变.但由于每一行都有$C$个位置($C$不小于任一行的 ...
- group 状压dp
应某些人要求,我把标签删掉了 这是一道好题. 一看$c<=16$果断状压,但是怎么压? 一个很显然的思路是,枚举上下两层的状态,每一层的状态极限有$C(c,c/2)$,c=16的时候有13000 ...
- POJ 3254 Corn Fields (状压DP,轮廓线DP)
题意: 有一个n*m的矩阵(0<n,m<=12),有部分的格子可种草,有部分不可种,问有多少种不同的种草方案(完全不种也可以算1种,对答案取模后输出)? 思路: 明显的状压DP啦,只是怎样 ...
- poj2411 Mondriaan's Dream (轮廓线dp、状压dp)
Mondriaan's Dream Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 17203 Accepted: 991 ...
- hdu5304 Eastest Magical Day Seep Group's Summer 状压dp+生成树
题目:http://acm.hdu.edu.cn/showproblem.php?pid=5304 16个点的无向图,问能生成多少个n条边的连通图.(即多一条边的树) 先n^3 * 2^n 枚举全部的 ...
- 多米诺骨牌放置问题(状压DP)
例题: 最近小A遇到了一个很有趣的问题: 现在有一个\(n\times m\)规格的桌面,我们希望用\(1 \times 2\)规格的多米诺骨牌将其覆盖. 例如,对于一个\(10 \times 11\ ...
- bzoj 1087 状压dp
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4130 Solved: 2390[Submit][ ...
- dp,状压dp等 一些总结
也就作业几题而已,分析一下提醒 最重要的就是,记住,没用的状态无论怎么转移最后都会是没用的状态,所以每次转移以后的有值的状态都是有用的状态. 几种思考方向: 第一种:枚举当前的状态,转移成另外一个状态 ...
- 牛客比赛-状压dp
链接:https://www.nowcoder.com/acm/contest/74/F来源:牛客网 德玛西亚是一个实力雄厚.奉公守法的国家,有着功勋卓著的光荣军史. 这里非常重视正义.荣耀.职责的意 ...
随机推荐
- InfluxDB从原理到实战 - 什么是InfluxDB
0x00 什么是InfluxDB InfluxDB是一个由InfluxData开发的开源时序型数据库,专注于海量时序数据的高性能读.高性能写.高效存储与实时分析等,在DB-Engines Rankin ...
- java并发之内存模型
java内存模型知识导图 一 并发问题及含义 并发编程存在原子性.可见性.有序性问题. 原子性即一系列操作要么都执行,要么都不执行. 可见性,一个线程对共享变量的修改,另一个线程可能不会马上看到. ...
- Solidity 编程实例--投票
Voting 投票 思路是为每张选票创建一个合约,每个投票选项提供一个短名称.合约创建者作为会长将会给每个投票参与人各自的地址投票权. 地址后面的人们可以选择自己投票或者委托信任的代表人替他们投票.在 ...
- .Net Core AA.FrameWork应用框架介绍
开发多年,一直在从社区获取开源的便利,也深感社区力量的重要性,今天开源一个应用基础框架AA.FrameWork,也算是回馈社区,做出一点点贡献,希望能够帮助类似当年入行的我. AA.FrameWork ...
- 关于Git的使用方法
1.查看Git的使用方法 : git 2.把当前文件夹变为一个git仓库 创建git仓库:git init 3.查看当前仓库文件变化情况:git status 4.添加修改:git add (可使用g ...
- Python3 解决 ModuleNotFoundError: No module named 'pygal.i18n' 问题
在获取国别码集通过导入模块pygal报以下问题: from pygal.i18n import COUNTRIES 解决方法: 安装模块 pip3 install pygal_maps_world ...
- sql 外键 on update cascade 和 on delete cascade 作用区别?
这是数据库外键定义的一个可选项,用来设置当主键表中的被参考列的数据发生变化时,外键表中响应字段的变换规则的.update 则是主键表中被参考字段的值更新,delete是指在主键表中删除一条记录:on ...
- 关于sqlmapapi一点记录
关于sqlmapapi自己练习的还是很少 今天看见freebuf上师傅的分享的内容 自己练习了一下 来自: https://www.freebuf.com/articles/web/204875.ht ...
- STL的vector略解
本文部分内容参考于这儿. vector 的基础知识,上文已经阐述地很详尽了.笔者谨给出 vector 的声明及其常用函数. 代码抬头需包含 #include<vector> using n ...
- spring boot 2.x文件路径映射问题汇总
当我们在运行可执行的java jar包的时候,我们肯定改变不了jar里面的内容,因此文件上传路径就成了我们必须考虑的一点问题,我们不能往直接这个jar包里面写文件,那么只能写在jar包外面,但是写到j ...