码迷,mamicode.com
首页 > 其他好文 > 详细

20180407模拟赛T1——Pro1

时间:2018-04-07 20:04:03      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:字符串长度   namespace   吐槽   ret   dig   names   include   end   Plan   

吐槽这题目名取得……

Pro1

为了入侵m*的机器,m__想了很多方法套m的密码。现在他终于得出了一个重要信息:m的密码是一个回文串。m__从m*处套出了若干个字符串,m__想知道对于每个字符串,最少可以在字符串最后加多少个字符,使得新字符串有可能成为密码。

数据范围

对于60%的数据 字符串长度≤103
对于100%的数据 字符串长度≤105 数据组数≤10

输入格式

若干行,每行一个字符串

输出格式

若干行,每行一个回文串

样例

Pro1.in

aaaa
abba
amanaplanacanal
xyz

Pro1.out

aaaa
abba
amanaplanacanalpanama
xyzyx

题解

这题暴力分还是挺多的。暴力么……主要是求最长回文字串嘛……

随便贴一份暴力

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
typedef long long ll;
#define dd c=getchar()
inline ll read(){
    ll x=0,f=1;char dd;
    for(;!isdigit(c);dd)if(c==‘-‘)f=-1;
    for(;isdigit(c);dd)x=(x<<1)+(x<<3)+(c^48);
    return x*f;
}
#undef dd
inline void write(ll x){
    if(x<0)putchar(‘-‘),x=-x;
    if(x>9)write(x/10);putchar(x%10|48);
}
const ll N=1e5+10;
char a[N];ll len;
inline bool check1(ll mid){
    for (ll i=1;mid+i<=len;i++)
        if (a[mid-i]!=a[mid+i]) return 0;
    for (ll j=mid*2-len-1;j>0;j--) putchar(a[j]);
    puts("");
    return 1;
}
inline bool check(ll mid){
    for (ll i=1;mid+i-1<=len;i++)
        if (a[mid-i]!=a[mid+i-1]) return check1(mid);
    for (ll j=(mid-1)*2-len;j>0;j--) putchar(a[j]);
    puts("");
    return 1;
}
int main(){
    freopen("pro1.in","r",stdin);
    freopen("pro1.out","w",stdout);
    while (scanf("%s",a+1)!=EOF){
        len=strlen(a+1);
        printf("%s",a+1);
        for (ll i=len>>1;i<=len;i++)
            if (check(i)) break;
    }return 0;
}

我的wa暴力

#include <cstdio>
#include <cstring>
#include <queue>

#define deb 0

using namespace std;

char a[100005];

queue<int>que;

char t;

inline bool pan(int l,int r)
{
    while(l<r)
    {
        if(a[l]==t) que.push(l);
        if(a[l]^a[r])return false;
        l++;r--;
    }
    return true;
}

inline bool pan2(int l,int r)
{
    while(l^r)
    {
        if(a[l]^a[r])return false;
        l++;r--;
    }
    return true;
}

int main()
{
    #if !deb
    freopen("pro1.in","r",stdin);
    freopen("pro1.out","w",stdout);
    #endif
    while(gets(a))
    {
        int ttt=0;
        int len=strlen(a);
        t=a[len-1];
        #if deb
        putchar(t);
        puts("");
        #endif
        for(int i=0;i<len;++i)
            if(t==a[i])
            {
                if(pan(i,len-1))
                {
                    ttt=i;
                    break;
                }
                while(!que.empty())
                {
                    i=que.front();
                    if(pan2(i,len-1))
                    {
                        ttt=i;
                        goto L1;
                    }
                    que.pop();
                }
            }
        L1:;
        if(ttt==0)
        {
            puts(a);
            continue;
        }
        for(int i=0;i<ttt;++i)putchar(a[i]);
        for(int i=len-1;i>=0;--i)putchar(a[i]);
        puts("");
    }
    #if !deb
    fclose(stdin);
    fclose(stdout);
    #endif
    return 0;
}

蛙的原因是只考虑回文串的字符个数是奇数的状态(只同时向左向右拓展)。

于是,为了防止这个错误,我们可以在每两个字符之间加一个‘#‘或’%‘(反正该一些奇怪的字符)

        gets(ch+1);
        len=strlen(ch+1);
        for(int i=1;i<=len;++i)s[i<<1]=ch[i],s[i<<1|1]=‘#‘;
        s[1]=-1,s[len<<1|1]=-2;//赋一些奇怪的字符
        len=len<<1|1;//拓展后的len 

于是就变成了Manacher算法

#include <cstdio>
#include <cstring>

using namespace std;

char ch[100005],s[200005];
int len,ppp,ok,ans[200005];

int main()
{
    freopen("pro1.in","r",stdin);
    freopen("pro1.out","w",stdout);
    while(gets(ch+1))
    {
        len=strlen(ch+1);
        for(int i=1;i<=len;++i)s[i<<1]=ch[i],s[i<<1|1]=‘#‘;
        s[1]=-1,s[len<<1|1]=-2;//赋一些奇怪的字符
        len=len<<1|1;//拓展后的len 
        ans[1]=0;ok=1;ans[len]=1;
        int tot=0;
        for(int i=2;i<len;++i)
        {
            ans[i]=(i>ok+ans[ok])?0:ans[(ok<<1)-i];
            if(i<=ok+ans[ok]&&i+ans[i]>ans[ok]+ok)  ans[i]=ok+ans[ok]-i;
            while(s[i-ans[i]-1]==s[i+ans[i]+1])ans[i]++,tot++;
            if(i+ans[i]>ok+ans[ok]) ok=i;
        }
        ppp=len;
        for(int i=2;i<len;++i)
            if(i+ans[i]==len-1)
            {
                ppp=i;break;
            }
        for(int i=1;i<=len;++i) if(!(i&1))  putchar(s[i]);
        for(int i=ppp-ans[ppp]-1;i;--i) if(!(i&1))  putchar(s[i]);
        puts("");
    }
    fclose(stdin);fclose(stdout);return 0;
}

让我们再来看看zhaotiesn大佬的玄学做法

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <ctime>
using namespace std;
#define Max 1000005
int n,l,r,mid,num[200],sum[Max];
char s[Max];
bool flag;

inline bool check(int x){
    /*for(int i=x+1;i<=((n+x+1)>>1);i++){
        if(s[i]!=s[n-i+x+1])return false;
    }*/
//  cout<<n<<" "<<(n+x)/2<<" "<<(n+x+1)/2<<" "<<x<<endl;
    if(sum[n]-sum[(n+x)/2]==sum[(n+x+1)/2]-sum[x]){
        for(int i=x+1;i<=((n+x+1)>>1);i++){
            if(s[i]!=s[n-i+x+1])return false;
        }
        return true;
    }else return false;
}

int main(){
    freopen("pro1.in","r",stdin);
    freopen("pro1.out","w",stdout);
    srand((int)time(NULL));
    for(int i=1;i<=200;i++)num[i]=rand()*rand()^rand()*rand()^rand();
    while(scanf("%s",s+1)!=EOF){
        n=strlen(s+1);flag=false;
        sum[0]=0;
        for(int i=1;i<=n;i++)sum[i]=sum[i-1]+num[int(s[i])];
        for(int i=0;i<=n;i++){
            if(check(i)){
                printf("%s",s+1);
                for(int j=i;j>=1;j--){
//                  printf("%c",s[j]);
                    putchar(s[j]);
                }
                puts("");
                flag=true;
            }
            if(flag)break;
        }
    }
    return 0;
}

20180407模拟赛T1——Pro1

标签:字符串长度   namespace   吐槽   ret   dig   names   include   end   Plan   

原文地址:https://www.cnblogs.com/pfypfy/p/8734229.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!