CF 1560E E. Polycarp and String Transformation(思维)

https://codeforces.com/contest/1560/problem/E

 

题意:

有一个串s和一个空串t,可以进行若干次以下操作,

每次操作先把s拼在t的后面,然后删掉s中的一种字母

直至s为空串

现在给出t,还原出s以及删除字母的顺序

 

原始思路:

t串中最后一个字母就是最后删除的字母,再往前碰到的就是倒数第二次删除的字母,再往前就是倒数第三次删除的字母,……,这样可以还原删除字母的顺序

假设字母一共有x种,最后一个删除的字母被拼接了x次,所以用这种字母在t串中的总次数除以x,就得到最后一次拼接的长度;以此类推往前,能够还原每次被拼接的串

每次还原都有限制不可以出现的字母,如果他们出现了就无解

但是只根据长度可能会导致顺序不符合,所以还原出的s还要按规则产生一个t,与给定的t相等才可以

#include<bits/stdc++.h>
 
using namespace std;
 
#define N 500004
 
char t[N];
 
char s[N],a[N],ss[N];
int sum[27][N];
 
bool vis[27];
 
int main()
{
    int T,n,all,need,last,div,tmp,len,L;
    bool tag,ok;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",t+1);
        n=strlen(t+1);
        reverse(t+1,t+n+1);
        for(int i=1;i<=26;++i) 
        {
            sum[i][0]=0;
            vis[i]=false;
        }
        all=0;
        for(int i=1;i<=n;++i)
        {
            if(!vis[t[i]-'a'+1]) 
            {
                a[++all]=t[i];
                vis[t[i]-'a'+1]=true;
            } 
            for(int j=1;j<=26;++j) sum[j][i]=sum[j][i-1];
            sum[t[i]-'a'+1][i]++;
        }
        div=all;
        last=0;
        need=1;
        for(int i=1;i<=26;++i) vis[i]=false;
        vis[a[1]-'a'+1]=true;
        ok=true;
        for(int i=1;i<=n && need<all;++i)
        {
            tag=true;
            if(!vis[t[i]-'a'+1])
            {
                ok=false;
                break;
            }
            for(int j=1;j<=need && tag;++j)
            {
                tmp=sum[a[j]-'a'+1][i]-sum[a[j]-'a'+1][last];
                if(tmp*(all-j+1)!=sum[a[j]-'a'+1][n]) tag=false;
            }
            if(tag)
            {
                ++need;
                vis[a[need]-'a'+1]=true;
                last=i;
                div--;
            }
        }
        if(need!=all) ok=false;
        else
        {
            reverse(a+1,a+all+1);
            len=L=0;
            for(int i=n;i>last;--i) s[++len]=t[i];
            reverse(t+1,t+n+1);
            for(int i=1;i<=26;++i) vis[i]=true;
            for(int i=1;i<=all;++i)
            {
                for(int j=1;j<=len;++j) 
                    if(vis[s[j]-'a'+1]) ss[++L]=s[j];
                vis[a[i]-'a'+1]=false;
            }
            if(L!=n) ok=false;
            for(int i=1;i<=L && ok;++i)
                if(ss[i]!=t[i]) ok=false; 
        }
        if(!ok) printf("-1\n");
        else
        {
            for(int i=1;i<=len;++i) printf("%c",s[i]);
            printf(" ");
            for(int i=1;i<=all;++i) printf("%c",a[i]); 
            printf("\n");
        }
    }
}
View Code

 

做麻烦了

t串中,以每个字母的最后出现位置从小到大排序,排序结果就是字母的删除顺序

然后就可以知道每个字母被拼接多少次,根据出现总次数判断拼接次数是否合法,同时得到s串长度

最后用s按规则产生一个t,判断与给定的t是否一样

不需要还原每次被拼接的串

 

posted @ 2021-09-01 21:35  TRTTG  阅读(42)  评论(0编辑  收藏  举报