转载请注明出处,谢谢http://blog.youkuaiyun.com/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;
}