1. 程式人生 > >20180407模擬賽T1——Pro1

20180407模擬賽T1——Pro1

pty AC gets -i blog str ring tin rand()

吐槽這題目名取得……

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