【区间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】
1 #include<iostream> 2 #include<cstdio> 3 #include<string> 4 #include<cstring> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 const int maxn=1e5+20; 9 const int maxm=1e6; 10 const int inf=0x3f3f3f3f; 11 12 struct Edge 13 { 14 int to,next,cap,flow; 15 }edge[maxm]; 16 int tol; 17 int head[maxn]; 18 int gap[maxn],dep[maxn],pre[maxn],cur[maxn]; 19 int num[1200]; 20 void init() 21 { 22 tol=0; 23 memset(head,-1,sizeof(head)); 24 memset(num,0,sizeof(num)); 25 } 26 27 void addedge(int u,int v,int w,int rw=0) 28 { 29 edge[tol].to=v; 30 edge[tol].cap=w; 31 edge[tol].next=head[u]; 32 edge[tol].flow=0; 33 head[u]=tol++; 34 edge[tol].to=u; 35 edge[tol].cap=rw; 36 edge[tol].next=head[v]; 37 edge[tol].flow=0; 38 head[v]=tol++; 39 } 40 41 int sap(int start,int end,int N) 42 { 43 memset(gap,0,sizeof(gap)); 44 memset(dep,0,sizeof(dep)); 45 memcpy(cur,head,sizeof(head)); 46 int u=start; 47 pre[u]=-1; 48 gap[0]=N; 49 int ans=0; 50 while(dep[start]<N) 51 { 52 if(u==end) 53 { 54 int Min=inf; 55 for(int i=pre[u];i!=-1;i=pre[edge[i^1].to]) 56 { 57 if(Min>edge[i].cap-edge[i].flow) 58 { 59 Min=edge[i].cap-edge[i].flow; 60 } 61 } 62 for(int i=pre[u];i!=-1;i=pre[edge[i^1].to]) 63 { 64 edge[i].flow+=Min; 65 edge[i^1].flow-=Min; 66 } 67 u=start; 68 ans+=Min; 69 continue; 70 } 71 bool flag=false; 72 int v; 73 for(int i=cur[u];i!=-1;i=edge[i].next) 74 { 75 v=edge[i].to; 76 if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u]) 77 { 78 flag=true; 79 cur[u]=pre[v]=i; 80 break; 81 } 82 } 83 if(flag) 84 { 85 u=v; 86 continue; 87 } 88 int Min=N; 89 for(int i=head[u];i!=-1;i=edge[i].next) 90 { 91 if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min) 92 { 93 Min=dep[edge[i].to]; 94 cur[u]=i; 95 } 96 } 97 gap[dep[u]]--; 98 if(!gap[dep[u]]) 99 { 100 return ans; 101 } 102 dep[u]=Min+1; 103 gap[dep[u]]++; 104 if(u!=start) 105 { 106 u=edge[pre[u]^1].to; 107 } 108 } 109 return ans; 110 } 111 int a[maxn]; 112 int n,m; 113 int bit[11]; 114 115 int main() 116 { 117 bit[0]=1; 118 for(int i=1;i<=10;i++) 119 { 120 bit[i]=bit[i-1]*2; 121 } 122 while(~scanf("%d%d",&n,&m)) 123 { 124 init(); 125 int x; 126 for(int i=1;i<=n;i++) 127 { 128 int temp=0; 129 for(int k=0;k<m;k++) 130 { 131 scanf("%d",&x); 132 if(x==1) 133 { 134 temp+=bit[k]; 135 } 136 } 137 num[temp]++; 138 } 139 int people=-inf; 140 for(int i=1024;i>=0;i--) 141 { 142 if(num[i]) 143 { 144 people=i; 145 break; 146 } 147 } 148 int planet=people+1; 149 for(int i=0;i<=1024;i++) 150 { 151 if(num[i]==0) 152 { 153 continue; 154 } 155 addedge(0,i,num[i]); 156 for(int k=0;k<m;k++) 157 { 158 if(i&(1<<k)) 159 { 160 addedge(i,planet+k,num[i]); 161 } 162 } 163 } 164 for(int i=planet;i<planet+m;i++) 165 { 166 scanf("%d",&a[i]); 167 addedge(i,planet+m,a[i]); 168 } 169 170 if(num[0]) 171 { 172 puts("NO"); 173 continue; 174 } 175 int res=sap(0,planet+m,planet+m+1); 176 if(res==n) 177 { 178 puts("YES"); 179 } 180 else 181 { 182 puts("NO"); 183 } 184 getchar(); 185 } 186 return 0; 187 }