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来源:牛客网 德玛西亚是一个实力雄厚.奉公守法的国家,有着功勋卓著的光荣军史. 这里非常重视正义.荣耀.职责的意 ...
随机推荐
- Thinkphp5.0第四篇
删除数据 当前模型删除 $user=UserModel::get(1); if($user->delete()){return '删除成功';} else{return '删除失败';} 根据主 ...
- python获取全国各个城市pm2.5、臭氧等空气质量
随着国家发展,中国很多城市的空气质量其实并不好,国家气象局会有实时统计,但是要去写爬虫爬取是十分麻烦的事情,并且官方网站也会做一些反爬虫措施,所以实现起来比较麻烦,最好的办法就是使用现成的免费接口,空 ...
- idea快捷键(mac下)
ctrl+/ 代码提示 command+o 搜索要进入的类并进入 command+shift+enter 另起一行 command+shift+u 在变成全大写与变成全小写之间切换 shift+鼠标滑 ...
- B-微积分-Sigmoid函数
目录 Sigmoid函数 一.Sigmoid函数详解 更新.更全的<机器学习>的更新网站,更有python.go.数据结构与算法.爬虫.人工智能教学等着你:https://www.cnbl ...
- ES6——新增数据结构Set与Map的用法
ES6 提供了新的数据结构 Set以及Map,下面我们来一一讲解. 一.Set 特性 似于数组,但它的一大特性就是所有元素都是唯一的,没有重复. 我们可以利用这一唯一特性进行数组的去重工作. 1.单一 ...
- (未完)经典Web漏洞实战演练靶场笔记
记录下自己写的经典Web漏洞靶场的write up,包括了大部分的经典Web漏洞实战场景,做个笔记. 0x01 任意文件下载漏洞 if(!empty($_GET['filename'])){ $fil ...
- 域渗透基础之NTLM认证协议
域渗透基础的两个认证协议ntlm和Kerberos协议是必须总结的~ 这篇简单总结下ntlm协议 晚上写下kerberos 0x01 NTLM简介 NTLM使用在Windows NT和Windows ...
- ASP.NET Core在 .NET Core 3.1 Preview 1中的更新
.NET Core 3.1 Preview 1现在可用.此版本主要侧重于错误修复,但同时也包含一些新功能. 这是此版本的ASP.NET Core的新增功能: 对Razor components的部分类 ...
- maven子项目导出成jar包及运行
第一步:选这idea右侧栏的maven projects 第二步:选中需要打包成jar包的项目下的lifecycle 第三步:选中package 第四步:点击开始导出 第五步:使用winRAR打开ja ...
- Jdk14 都要出了,Jdk8 的时间处理姿势还不了解一下?
当前时间:2019年10月24日.距离 JDK 14 发布时间(2020年3月17日)还有多少天? // 距离JDK 14 发布还有多少天? LocalDate jdk14 = LocalDate.o ...