zoukankan      html  css  js  c++  java
  • 【区间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 }
    View Code
  • 相关阅读:
    ObjectiveC语法快速参考
    IIS网站全部显示无权访问需要登录
    如何让自己的网站尽快收录绍兴114导航
    asp.net的运行原理
    WPF学习视频资料
    Asp.net MVC3 自定义HtmlHelper控件
    Unity3D中C#和JS的方法互相調用
    对于冒泡算法的思考,大牛可一笑而过~~
    2013年年前瞻望与计划
    使用vs2010编辑Unity脚本,配置方法
  • 原文地址:https://www.cnblogs.com/itcsl/p/7128364.html
Copyright © 2011-2022 走看看