【GDOI2017 day2】小学生语文题

来源:互联网 发布:合肥大数据产业峰会 编辑:程序博客网 时间:2024/04/30 14:23

Description

这里写图片描述

Solution

比赛的时候打了个信仰贪心,结果只拿到了10分,但是后来打完正解之后才发现贪心分答案处理好像有些问题,要是把这个纠正过来不知道还能多拿多少分。
这个很明显可以倒着DP。
设f[i][j]表示a串i~n都匹配完成,b串用到了j~n(有些可能不动,有些可能抽了出来)
我们考虑怎么转移:
我们知道i,j的状态只可能从(i+1,j),(i+1,j+1),(i,j+1)转移过来
1、从(i+1,j)转移过来,那么就是说抽出来的可以把i填满,那么判断一下现在b串这个字符的数量是否比a串这个字符的数量大(在a的i+1~n和b的j~n,预处理一个数组减一下–b[s[i]][j]-a[s[i]][i+1]),然后f[i][j]就与f[i+1][j]取一个min。
2、从(i+1,j+1)转移过来,那么就是说当前的这个位置可以不用动s[i]=st[j],那么f[i][j]与f[i+1][j+1]取一个min
上面的是不用抽出来的情况(不用贡献+1),所以要先更新状态,否则会有问题
3、从(i,j+1)转移过来,就是说现在只把j抽出来不匹配,那么f[i][j]和f[i][j+1]+1去一个min
还要预处理一下,f[n+1]的预处理,f[n+1][n+1]=0,f[n+1][n]=1,……,f[n+1][1]=n,就是一个个抽出来不匹配。
然后f[1][1]就是答案。
然后就是方案数要怎么求。我们用一个g[i][j][0,1]在更新f[i][j]的时候存储它的上一个状态的i,j
我们知道只有从(i,j+1)过来的时候才会抽出来,那么就是说在转态从(1,1)向后转移的时候,当i不变j边的时候,这些状态是要抽出来的,我是一直找出下一个不等于i的转态,然后标记(这些是不用抽出来的),然后把标记翻转一下就好了。
最后知道了这些要抽出来,那么倒着模拟一遍,先把要抽出来的放进一个桶里面,然后如果能匹配就匹配,否则把桶里的东西抽出来匹配。
最后得到了一个答案数组,要考虑相对位置,只用考虑每个i这个答案对i+1~n的答案的影响,如果影响了就+1……很简单
找方案打的有些复杂,应该还有更快的方法。不过这个好想好理解。

Code

#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<math.h>#define fo(i,a,b) for(i=a;i<=b;i++)#define fod(i,a,b) for(i=a;i>=b;i--)using namespace std;const int maxn=2007;int i,j,k,l,t,n,m,ans,pan,o,x,y,hou;int f[maxn][maxn],g[maxn][maxn][2],cas,se[27][maxn];char s[maxn],st[maxn];int a[maxn][26],b[maxn][26],an[maxn][2],c[maxn];int main(){    freopen("chinese.in","r",stdin);    freopen("chinese.out","w",stdout);    for(scanf("%d",&cas);cas;cas--){        scanf("%s",s+1);scanf("%s",st+1);n=strlen(s+1);        memset(f,127,sizeof(f));memset(g,0,sizeof(g));        pan=f[0][0];fod(i,n+1,1)f[n+1][i]=n+1-i;        memset(a,0,sizeof(a));memset(b,0,sizeof(b));        fod(i,n,1){            fo(j,0,25)a[i][j]=a[i+1][j],b[i][j]=b[i+1][j];            a[i][s[i]-'a']++,b[i][st[i]-'a']++;        }        fod(i,n,1){            fod(j,n,1){                if(f[i+1][j]!=pan&&f[i][j]>f[i+1][j]&&b[j][s[i]-'a']-a[i+1][s[i]-'a']>0){                    f[i][j]=f[i+1][j];                    g[i][j][0]=i+1,g[i][j][1]=j;                }                if(f[i+1][j+1]!=pan&&f[i][j]>f[i+1][j+1]&&s[i]==st[j]){                    f[i][j]=f[i+1][j+1];                    g[i][j][0]=i+1,g[i][j][1]=j+1;                }            }            fod(j,n,1){                if(f[i][j+1]!=pan&&f[i][j]>f[i][j+1]+1){                    f[i][j]=f[i][j+1]+1;                    g[i][j][0]=i,g[i][j][1]=j+1;                }            }        }        printf("%d\n",f[1][1]);        x=1,y=1;o=0;memset(se,0,sizeof(se));memset(c,0,sizeof(c));hou=n;        while(x!=n+1){            while(g[x][y][0]==x)y=g[x][y][1];            if(g[x][y][1]!=y)c[y]++,y++;            x++;        }        fo(i,1,n){c[i]=1-c[i];if(c[i])se[st[i]-'a'][++se[st[i]-'a'][0]]=i;}        fod(i,n,1){            if(!hou)break;            if(!c[i]){                while(s[hou]!=st[i]){                    an[++o][0]=se[s[hou]-'a'][se[s[hou]-'a'][0]--],an[o][1]=i+1;                    hou--;                }                hou--;            }        }        fod(j,hou,1){            i=s[j]-'a';            an[++o][0]=se[i][se[i][0]--],an[o][1]=1;        }        fo(i,1,o){            fo(j,i+1,o){                if(an[i][0]>=an[j][0]&&an[j][0]>=an[i][1])an[j][0]++;                if(an[i][0]>an[j][1]&&an[j][1]>an[i][1])an[j][1]++;            }        }        fo(i,1,o)printf("%d %d\n",an[i][0],an[i][1]);    }}
1 0
原创粉丝点击