官方题解不是很详细

首先有一个结论:若A=pa+sa B=pb+sb 

A、B串循环同构,则可以构造一个可行方案(pa,sb) (sa,pb)中有一个是最长匹配,这个不难用反证法证明。

对于s1,s2串,我们穷举s1的每一个后缀i,设s1[i..i+len-1]=s2[0..len-1] len是最长匹配

那么不难得到,如果存在k使得k<=len且s1[0..i-1]=s2[k..k+i-1]

那么,两串前缀s1[0..i+k-1]为循环同构

因此我们预处理w[i][j]表示s1[0..i]=s2[j..j+i]是否相等,w数组我们可用bitset压位存储

求出这个数组我们只需要建立后缀数组然后顺着height[]找即可

下面我们在将变量代换,前缀p=i+k-1循环同构的条件为i-1<=p<=len+i-1且w[i-1][p]为1

这个条件我们在压位的情况下可以用位运算处理

问题得解

  1 #include<bits/stdc++.h>
  2 
  3 using namespace std;
  4 bitset<10000> w[10010],ans,pre[10010],tmp;
  5 char s2[20010],s1[20010];
  6 int d[20],lg[20010],h[20010],s[20010],rk[20010],sa[20010],x[20010],y[20010],a[20010];
  7 int f[20010][16],n;
  8 pair<int,int> q[20010];
  9 bool cmp(int a,int b,int j)
 10 {
 11     if (y[a]==y[b])
 12     {
 13         if (a+j<=n&&b+j<=n) return y[a+j]!=y[b+j];
 14         else if (a+j>n&&b+j>n) return 0;
 15         else return 1;
 16     }
 17     return y[a]!=y[b];
 18 }
 19 
 20 void suffix()
 21 {
 22     int m=28;
 23     memset(s,0,sizeof(s));
 24     for (int i=1; i<=n; i++) s[a[i]]++;
 25     for (int i=1; i<=m; i++) s[i]+=s[i-1];
 26     for (int i=n; i; i--) sa[s[a[i]]--]=i;
 27     int p=1; rk[sa[1]]=1;
 28     for (int i=2; i<=n; i++)
 29     {
 30         if (a[sa[i]]!=a[sa[i-1]]) ++p;
 31         rk[sa[i]]=p;
 32     }
 33     int j=1; m=p;
 34     while (m<n)
 35     {
 36         memcpy(y,rk,sizeof(rk));
 37         memset(s,0,sizeof(s));
 38         p=0;
 39         for (int i=n-j+1; i<=n; i++) x[++p]=i;
 40         for (int i=1; i<=n; i++)
 41             if (sa[i]>j) x[++p]=sa[i]-j;
 42         for (int i=1; i<=n; i++) s[rk[i]=y[x[i]]]++;
 43         for (int i=1; i<=m; i++) s[i]+=s[i-1];
 44         for (int i=n; i; i--) sa[s[rk[i]]--]=x[i];
 45         rk[sa[1]]=1; p=1;
 46         for (int i=2; i<=n; i++)
 47         {
 48             if (cmp(sa[i],sa[i-1],j)) ++p;
 49             rk[sa[i]]=p;
 50         }
 51         m=p; j<<=1;
 52     }
 53     p=0; h[1]=0;
 54     for (int i=1; i<=n; i++)
 55     {
 56         if (rk[i]==1) continue;
 57         int j=sa[rk[i]-1];
 58         while (i+p<=n&&j+p<=n&&a[i+p]==a[j+p]) ++p;
 59         h[rk[i]]=p;
 60         if (p) p--;
 61     }
 62 }
 63 
 64 int ask(int x,int y)
 65 {
 66     int k=lg[y-x+1];
 67     return min(f[x][k],f[y-d[k]+1][k]);
 68 }
 69 
 70 void rmq()
 71 {
 72     for (int i=1; i<=n; i++)
 73         f[i][0]=h[i];
 74     for (int j=1; j<=lg[n]; j++)
 75     {
 76         for (int i=1; i<=n; i++)
 77             if (i+d[j]-1<=n) f[i][j]=min(f[i][j-1],f[i+d[j-1]][j-1]);
 78             else break;
 79     }
 80 }
 81 
 82 int main()
 83 {
 84  //   freopen("1002.in","r",stdin);
 85     d[0]=1; lg[1]=0;
 86     for (int i=1; i<=15; i++)
 87     {
 88         d[i]=d[i-1]*2;
 89         for (int j=d[i-1]; j<=min(20005,d[i]-1); j++) lg[j]=i-1;
 90     }
 91     pre[0][0]=1;
 92     for (int i=1; i<10000; i++)
 93     {
 94         pre[i]=pre[i-1];
 95         pre[i][i]=1;
 96     }
 97     while (scanf("%s%s",s1,s2)!=EOF)
 98     {
 99         int l=strlen(s1);
100         n=0;
101         for (int i=0; i<l; i++) a[++n]=s1[i]-'a'+1;
102         a[++n]=27;
103         for (int i=0; i<l; i++) a[++n]=s2[i]-'a'+1;
104         a[n+1]=0;
105         suffix(); rmq();
106         for (int i=0; i<l; i++) w[i].reset();
107         int len=n,m=0;
108         for (int i=rk[1]+1; i<=n; i++)
109         {
110             len=min(len,h[i]);
111             if (!len) break;
112             else if (sa[i]>l+1) q[++m]=make_pair(len-1,sa[i]-l-2);
113         }
114         len=h[rk[1]];
115         for (int i=rk[1]-1; i; i--)
116         {
117             if (!len) break;
118             else if (sa[i]>l+1) q[++m]=make_pair(len-1,sa[i]-l-2);
119             len=min(len,h[i]);
120         }
121         sort(q+1,q+1+m);
122         tmp.reset(); int j=m;
123         for (int i=l-1; i>=0; i--)
124         {
125             while (j&&q[j].first==i) tmp[q[j--].second]=1;
126             w[i]=tmp;
127         }
128         ans.reset();
129         for (int i=0; i<l; i++)
130         {
131             int x=rk[i+1],y=rk[l+2];
132             if (x>y) swap(x,y);
133             len=ask(x+1,y);
134             if (len)
135             {
136                 if (i) ans|=(pre[i-1]^pre[i+len-1])&(w[i-1]<<(i-1));
137                 else ans|=pre[len-1];
138             }
139         }
140         for (int i=0; i<l; i++)
141             if (ans[i]) printf("1"); else printf("0");
142         puts("");
143     }
144 }
View Code

 

posted on 2017-02-26 22:03  acphile  阅读(219)  评论(0编辑  收藏  举报