【区间DP+好题】String painter
https://www.bnuoj.com/v3/contest_show.php?cid=9149#problem/G
【题意】
给定两个长度相同的字符串A,B。每次操作都能把A中的任意一个子段变成相同的字符,问最少操作多少次A能变成B?
【思路】
*****************************************************************************************************
dp[i][j]表示i-j区间内的最少次数
先操作第二个字符串,我们先假设第i个字符的位置需要喷刷一次,对于所有的dp[i][j]=dp[i+1][j]+1、
在i-j区间内,如果有第k个跟第i个相同,那么就可以将i-j区间借助k分成两部分dp[i][j]=min(dp[i+1][k]+dp[k+1][j]);
处理完第2个字符串后,我们就要看第一个字符串究竟需要喷刷多少次了,用ans[i]记录0-i区间第二个字符串得出的喷刷次数,如果第一个字符串的i位置与第二个字符串的i位置相同,那么这个位置就不用喷刷了,ans[i]=ans[i-1],如果不相同,就要就要借助一个位于o-i区间内的变量来分割开。
************************************************************************************************************
对于dp[i][j] 来说最差的就是1+dp[i+1][j]咯,那怎么减少呢。。。 如果(i,j]里面也有个k使得b[i] == b[k]那么得话, 可以刷[i,k]这么长的一段,那么就有可能减少1. 但是存在问题,如果有一段跨越了k怎么办。。。 嗯,这个问题是不会出现的, 因为在[i,k]刷了b[i].如果跨越了k那么之前在b[k]刷的颜色就没了,所以是不允许有跨段的, 所以要写成&&想写成 dp[i][j] = dp[i+1][k] + dp[k+1][j]。 为什么不可以跨段 可以思考 BRBR 。 然后后来的那个 一段 要么是可以分段刷的,要么是不可以分段刷的。-
************************************************************************************************************
先计算出空串涂成b串的代价,用dp[i][j]存储区间[i, j]涂成和b串一样的最小代价。
因为字符都不相同,那么代价的优化点就在于b串中相同的字符。
dp[i][j] = min(dp[i+1][j]+1, dp[i+1][k]+dp[k+1][j]); (i+1<=k<=j && b[k] == b[i])
b[i]可以在涂区间[i+1, k]时顺带涂上。 处理时需要注意边界。
整理我们已经有的信息dp[i][j],把空串变成b[i] - b[j]的字符串所需的最小代价。
设置ans[i]为a[0] - a[i]的字符串变成b[0] - b[i]所需的最小代价。
则状态转移:
a[i] == b[i] ans[i] = ans[i-1];
a[i] != b[i] ans[i] = min(ans[i], ans[j] + dp[j+1][i]); 把区间[j+1, i]当做空串来处理。
************************************************************************************************************
例如zzzzzfzzzzz,长度为11,我们就将下标看做0~10
先将0~10刷一次,变成aaaaaaaaaaa
1~9刷一次,abbbbbbbbba
2~8:abcccccccba
3~7:abcdddddcba
4~6:abcdeeedcab
5:abcdefedcab
这样就6次,变成了s2串了
第二个样例也一样
先将0~10刷一次,变成ccccccccccb
1~9刷一次,cdddddddddcb
2~8:cdcccccccdcb
3~7:cdcdddddcdcb
4~6:cdcdcccdcdcb
5:cdcdcdcdcdcb
最后竟串尾未处理的刷一次
就变成了串2cdcdcdcdcdcd
所以一共7次
************************************************************************************************
【Accepted】
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=1e5+;
const int maxm=1e6;
const int inf=0x3f3f3f3f; struct Edge
{
int to,next,cap,flow;
}edge[maxm];
int tol;
int head[maxn];
int gap[maxn],dep[maxn],pre[maxn],cur[maxn];
int num[];
void init()
{
tol=;
memset(head,-,sizeof(head));
memset(num,,sizeof(num));
} void addedge(int u,int v,int w,int rw=)
{
edge[tol].to=v;
edge[tol].cap=w;
edge[tol].next=head[u];
edge[tol].flow=;
head[u]=tol++;
edge[tol].to=u;
edge[tol].cap=rw;
edge[tol].next=head[v];
edge[tol].flow=;
head[v]=tol++;
} int sap(int start,int end,int N)
{
memset(gap,,sizeof(gap));
memset(dep,,sizeof(dep));
memcpy(cur,head,sizeof(head));
int u=start;
pre[u]=-;
gap[]=N;
int ans=;
while(dep[start]<N)
{
if(u==end)
{
int Min=inf;
for(int i=pre[u];i!=-;i=pre[edge[i^].to])
{
if(Min>edge[i].cap-edge[i].flow)
{
Min=edge[i].cap-edge[i].flow;
}
}
for(int i=pre[u];i!=-;i=pre[edge[i^].to])
{
edge[i].flow+=Min;
edge[i^].flow-=Min;
}
u=start;
ans+=Min;
continue;
}
bool flag=false;
int v;
for(int i=cur[u];i!=-;i=edge[i].next)
{
v=edge[i].to;
if(edge[i].cap-edge[i].flow&&dep[v]+==dep[u])
{
flag=true;
cur[u]=pre[v]=i;
break;
}
}
if(flag)
{
u=v;
continue;
}
int Min=N;
for(int i=head[u];i!=-;i=edge[i].next)
{
if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min)
{
Min=dep[edge[i].to];
cur[u]=i;
}
}
gap[dep[u]]--;
if(!gap[dep[u]])
{
return ans;
}
dep[u]=Min+;
gap[dep[u]]++;
if(u!=start)
{
u=edge[pre[u]^].to;
}
}
return ans;
}
int a[maxn];
int n,m;
int bit[]; int main()
{
bit[]=;
for(int i=;i<=;i++)
{
bit[i]=bit[i-]*;
}
while(~scanf("%d%d",&n,&m))
{
init();
int x;
for(int i=;i<=n;i++)
{
int temp=;
for(int k=;k<m;k++)
{
scanf("%d",&x);
if(x==)
{
temp+=bit[k];
}
}
num[temp]++;
}
int people=-inf;
for(int i=;i>=;i--)
{
if(num[i])
{
people=i;
break;
}
}
int planet=people+;
for(int i=;i<=;i++)
{
if(num[i]==)
{
continue;
}
addedge(,i,num[i]);
for(int k=;k<m;k++)
{
if(i&(<<k))
{
addedge(i,planet+k,num[i]);
}
}
}
for(int i=planet;i<planet+m;i++)
{
scanf("%d",&a[i]);
addedge(i,planet+m,a[i]);
} if(num[])
{
puts("NO");
continue;
}
int res=sap(,planet+m,planet+m+);
if(res==n)
{
puts("YES");
}
else
{
puts("NO");
}
getchar();
}
return ;
}
【区间DP+好题】String painter的更多相关文章
- 又一道区间DP的题 -- P3146 [USACO16OPEN]248
https://www.luogu.org/problemnew/show/P3146 一道区间dp的题,以区间长度为阶段; 但由于要处理相邻的问题,就变得有点麻烦; 最开始想了一个我知道有漏洞的方程 ...
- poj 2955 Brackets (区间dp基础题)
We give the following inductive definition of a “regular brackets” sequence: the empty sequence is a ...
- 状态压缩---区间dp第一题
标签: ACM 题目 Gappu has a very busy weekend ahead of him. Because, next weekend is Halloween, and he is ...
- 区间DP UVA 10739 String to Palindrome
题目传送门 /* 题意:三种操作,插入,删除,替换,问最少操作数使得字符串变成回文串 区间DP:有一道类似的题,有点不同的是可以替换,那么两端点不同的时候可以替换掉一个后成回文, 即dp[j+1][k ...
- poj 2955 区间dp入门题
第一道自己做出来的区间dp题,兴奋ing,虽然说这题并不难. 从后向前考虑: 状态转移方程:dp[i][j]=dp[i+1][j](i<=j<len); dp[i][j]=Max(dp[i ...
- 区间DP UVA 1351 String Compression
题目传送门 /* 题意:给一个字符串,连续相同的段落可以合并,gogogo->3(go),问最小表示的长度 区间DP:dp[i][j]表示[i,j]的区间最小表示长度,那么dp[i][j] = ...
- 二叉树问题(区间DP好题)
二叉树问题 时间限制: 1 Sec 内存限制: 128 MB 题目描述 Petya Bulochkin很幸运:他得到了一份在"Macrohard"公司的工作.他想要展现他的才华, ...
- codeforces 1140D(区间dp/思维题)
D. Minimum Triangulation time limit per test 2 seconds memory limit per test 256 megabytes input sta ...
- 区间dp板子题:[noi1995]石子合并
非常经典的区间dp模板 对于每一个大于二的区间 我们显然都可以将它拆分成两个子序列 那么分别计算对于每个取最优值即可 #pragma GCC optimize("O2") #inc ...
- zoj3469 区间dp好题
/* 按坐标排序 以餐厅为起点向两边扩展区间 dp[i][j][0]表示送完区间[i,j]的饭后停留在左边的代价 dp[i][j][1]表示送完区间[i,j]的饭后停留在右边的代价 */ #inclu ...
随机推荐
- 随机带权选取文件中一行 分类: linux c/c++ 2014-06-02 00:11 344人阅读 评论(0) 收藏
本程序实现从文件中随即选取一行,每行被选中的概率与改行长度成正比. 程序用一次遍历,实现带权随机选取. 算法:假设第i行权重wi(i=1...n).读取到文件第i行时,以概率wi/(w1+w2+... ...
- 443 String Compression 压缩字符串
给定一组字符,使用原地算法将其压缩.压缩后的长度必须始终小于或等于原数组长度.数组的每个元素应该是长度为1 的字符(不是 int 整数类型).在完成原地修改输入数组后,返回数组的新长度.进阶:你能否仅 ...
- sdut2355Binary Search Heap Construction
链接 捣鼓了一下午..按堆建树 写完交 返回TLE..数据不大 感觉不会超了 无奈拿了数据来看什么奇葩数据会超 发现数据跟我输出不一样 看了好久才明白理解错题意了 给出的字符串有两个标签 按前一个来建 ...
- android开发学习——This support library should not use a different version
http://blog.csdn.net/mvpstevenlin/article/details/55209966 完美解决系列
- laravel5.5文件上传
/** * 上传文件 * @param Request $request * @return array */ public function upload(Re ...
- php中读取以及写入文件的方法总结
==>读取文件内容(方法一) $fileData = fread($fileStream,filesize($filePath)); 注意: 文本文件读取到网页上显示时,由于换行符不被解释,文本 ...
- mac 下使用gcc 编译c函数
mac 终端其实和window 的cmd类似,由于mac 的os x 采用了unix 系统,所以,各种类似UNIX下的命令都有用.最近在看computer science ,用到了命令行. 下面是一个 ...
- R in action 读书笔记(1)--第五章:高级数据管理
5.2.1数学函数 函数 描述 abs(x) 绝对值 sqrt(x) 平方根 ceiling(x) 不小于x的最小整数 floor(x) 不大于x的最大整数 trunc(x) 向0的方向截取的X中的整 ...
- redisd的非持久化配置
如何关闭redis持久化?我的需求是只把redis当作缓存来用,所以持久化到硬盘对我的需求来说没有意义. 修改redis配置文件,redis.conf 第115行左右. 1.注释掉原来的持久化规则 # ...
- tab切换组件nz-tab
<nz-card [nzBordered]="true" nzTitle="卡片标题"> <nz-card style="width ...