CF 119D String Transformation(KMP,雜湊,列舉,各種優化)

acm_cxlove發表於2012-12-26

轉載請註明出處,謝謝http://blog.csdn.net/ACM_cxlove?viewmode=contents    by---cxlove  

題目:有兩個串,s,f  f(s, i, j) = s[i + 1... j - 1] + r(s[j... n - 1]) + r(s[0... i])

通過二元組(i,j)對原串s進行變換,得到新的串,現在要你求這個二元組

http://codeforces.com/problemset/problem/119/D 

哈哈,爽,終於A了

第一次在CF上除錯這麼艱辛,TLE+WA刷了好多

我們將兩個串表示成a,b,分為三個部分

a  (  1  ,  2  ,  3  )     a'表示a的反序

那麼b ( 2  ,  3'  ,   1' )    b'表示b的反序

我的做法是,第一步,列舉i,首先我們可以看到a和b‘的最長公共字首。

由於 題目要求i最大,所以先求出a和b'的最長公共字首長度,mx+1

然後i便可以從mx可能列舉。

接下來相當於列舉j,但是直接列舉肯定會TLE

可以發現b的字尾除了1'之後,便是a’的字首。

那麼我們用a'和b做一次KMP,記錄對於b中的某個位置,能匹配的最遠距離pos[]

但是並不一定j越遠就好,所以列舉的時候,從pos[]出發,通過next[]陣列就能列舉到可能的j

這樣列舉出來的,肯定是滿足1,3這兩個部分

剩下的就是判斷兩個串的剩下部分也就是部分2是否匹配了。這一部分通過HASH就能O(1)處理。

但是這樣還是會TLE,因為可以知道像aaaaaaaaaaabaaaaaaaaa這種串,通過next陣列轉移很慢的。還是相當於列舉

這裡我又加了個優化,用b串和a串直接跑一次KMP,記錄對於a中的某個位置,和b的字首最長能匹配的長度dp[]。

那麼在列舉i之後,列舉j,通過這個長度 能作一次剪枝

但是這裡又WA了很久。這是因為在處理dp[]陣列的時候,我只是在向前移動匹配的時候,轉移了dp[]陣列,其實是不對的。即使不能匹配,通過next[]陣列,也是能得到字尾的字首和字首是匹配的,也是可以轉移的。

以上想法,純屬是自己不成熟的做法,而且也表述不清

歡迎交流。可以看下程式碼

#include<iostream>  
#include<cstdio>  
#include<map>  
#include<cstring>  
#include<cmath>  
#include<vector>  
#include<algorithm>  
#include<set>  
#include<string>  
#include<queue>  
#define inf 1600005  
#define M 40  
#define N 1000005
#define maxn 300005  
#define eps 1e-12
#define zero(a) fabs(a)<eps  
#define Min(a,b) ((a)<(b)?(a):(b))  
#define Max(a,b) ((a)>(b)?(a):(b))  
#define pb(a) push_back(a)  
#define mp(a,b) make_pair(a,b)  
#define mem(a,b) memset(a,b,sizeof(a))  
#define LL long long  
#define MOD 1000000007
#define lson step<<1
#define rson step<<1|1
#define sqr(a) ((a)*(a))  
#define Key_value ch[ch[root][1]][0]  
#define test puts("OK");  
#define pi acos(-1.0)
#define lowbit(x) ((-(x))&(x))
#define HASH1 1331
#define HASH2 10001
#pragma comment(linker, "/STACK:1024000000,1024000000")  
using namespace std;
char a[N],a_2[N],b[N];
int la,lb;
int next[N];
int pos[N];
int dp[N];
LL fac1[N]={1},fac2[N]={1};
LL h11[N]={0},h21[N]={0};
LL h12[N]={0},h22[N]={0};
void get_next(char *s,int len){
    next[0]=-1;
    int i=0,j=-1;
    while(i<len){
        if(j==-1||s[i]==s[j]){
            i++;j++;
            next[i]=j;
        }
        else j=next[j];
    }
}
void match(char *pat,int lp,char *str,int ls,int flag){
    int i=0,j=0;
    while(i<lp&&j<ls){
        if(i==-1||pat[i]==str[j]){
            if(!flag) pos[j]=i;
            if(flag&&i!=-1){
                dp[j-i]=max(dp[j-i],i+1);
            }
            i++;j++;
        }
        else{
            i=next[i];
            dp[j-i]=max(dp[j-i],i+1);
        }
        if(i==lp) i=next[i];
    }
}
LL get(int l,int r,LL *hash,LL *fac){
    l++;r++;
    return hash[r]-hash[l-1]*fac[r-l+1];
}
int main(){
    //freopen("input.txt","r",stdin);
    for(int i=1;i<N;i++){
        fac1[i]=fac1[i-1]*HASH1;
        fac2[i]=fac2[i-1]*HASH2;
    }
    while(gets(a)!=NULL&&gets(b)!=NULL){
        la=strlen(a);lb=strlen(b);
        if(la!=lb){
            //if(a[0]==a[1]&&a[2]==a[3]&&a[2]==' ') cout<<3333333333<<endl;
            printf("-1 -1\n");
            continue;
        }
        for(int i=0;i<la;i++)
            a_2[i]=a[la-i-1];
        for(int i=1;i<=la;i++){
            h11[i]=h11[i-1]*HASH1+a[i-1];
            h12[i]=h12[i-1]*HASH2+a[i-1];
        }
        for(int i=1;i<=lb;i++){
            h21[i]=h21[i-1]*HASH1+b[i-1];
            h22[i]=h22[i-1]*HASH2+b[i-1];
        }
        get_next(a_2,la);
        match(a_2,la,b,lb,0);
        mem(dp,-1);
        get_next(b,lb);
        match(b,lb,a,la,1);
        int l=-1,r=-1,mx=-1;
        for(int i=0;i<la;i++)
            if(a[i]==b[lb-i-1]){
                mx=i;
            }
            else break;
        for(int i=min(la-2,mx);i>=0;i--){
            int p=pos[lb-i-2];

            while(p>=0){
                int j=la-p-1;
                if(j-i-1>dp[i+1]&&j-i-1!=0) break;
                if(i+1==j){
                    l=i,r=j;
                }
                else{
                    LL t1=get(i+1,j-1,h11,fac1),t2=get(0,j-i-2,h21,fac1);
                    LL t3=get(i+1,j-1,h12,fac2),t4=get(0,j-i-2,h22,fac2);
                    if(t1==t2&&t3==t4) l=i,r=j;
                }
                p=next[p];
                if(l!=-1) break;
            }
            if(l!=-1) break;
        }
        printf("%d %d\n",l,r);
    }
    return 0;
}






相關文章