父亲醉酒

来源:互联网 发布:爱奇艺软件一直唤醒 编辑:程序博客网 时间:2024/06/02 20:57

醉酒

drunk.pas/c/cpp)

【题目描述】

X家住在一条东西向的大街上。在他们家的东面,自东向西依次分布着n幢相似的房屋,编号为1到n,可以用一个长度为n的字符串表示这n幢房屋的颜色。

X的父亲经常喝醉酒,每次醉酒后他都会稀里糊涂地走到第Ai幢房屋前,然后坚信他现在第Bi幢房屋前。虽然他喝醉了,但是他依然能分清每幢房屋的颜色,并且掏出地图进行比较,只有房屋颜色和地图上一致时,他才会继续向西走。当他发现自己的错误或者不能前进时,就会停下来。现在,小X记录下了每次的数据Ai和Bi,他希望知道父亲最多走过多少幢相同颜色的房屋。

【输入格式】

第一行两个数n和m,表示n幢房屋和m次询问。

第二行一个长度为n的字符串,仅包含大写字母。

接下来m行,每行两个数Ai和Bi。

【输出格式】

m行,每个一个数,表示小X的父亲父亲最多走过多少幢相同颜色的房屋。

【输入样例】

10 6

AABBCCAABB

1 7

7 1

3 4

4 9

2 5

5 5

【输出样例】

4

4

1

1

0

6

【数据范围】

对于60%的数据,n,m≤100。

对于80%的数据,n≤1000。

对于100%的数据,n,m≤100000,Ai,Bi≤n。


分析:

裸的字符串最长公共前缀,后缀数组即可。当然,二分加hash也是可以的。

后缀数组基础。 字符串匹配hash。

参考程序:

#include<cstdio>#include<algorithm>#define maxn 210000using namespace std;int rank[maxn],sa[maxn],tmp[maxn],lcp[maxn],a[maxn];int f[maxn][25];int n,m,k;bool cmp_sa(int i,int j){if (rank[i] != rank[j])return rank[i]<rank[j];int ri=i+k<=n?rank[i+k]:-1;    int rj=j+k<=n?rank[j+k]:-1;    return ri<rj;}int query(int x,int y){int k=0;while ((1<<(k+1))<=y-x+1)k++;//printf("%d %d %d %d %d %d\n",x,y,y-(1<<k)+1,k,f[x][k],f[y-(1<<k)+1][k]);return min(f[x][k],f[y-(1<<k)+1][k]);}int main(){freopen("drunk.in","r",stdin);freopen("drunk.out","w",stdout);scanf("%d%d",&n,&m);for (int i=0;i<n;i++){char cmd=getchar();while(!('A'<=cmd && cmd<='Z'))cmd=getchar();rank[i]=cmd-'A',sa[i]=i,a[i]=cmd-'A'+1;}sa[n]=n;rank[n]=-1;for (k=1;k<=n;k<<=1){sort(sa,sa+n+1,cmp_sa);tmp[sa[0]]=0;for (int i=1;i<=n;i++)tmp[sa[i]]=tmp[sa[i-1]]+(cmp_sa(sa[i-1],sa[i])?1:0);for (int i=0;i<=n;i++)rank[i]=tmp[i];}/*for (int i=0;i<=n;i++){printf("%d %d %d\n",i,sa[i],rank[i]);for (int j=sa[i];j<n;j++)printf("%d ",a[j]);printf("\n\n");}*/int h=0;for (int i=0;i<=n;i++)rank[sa[i]]=i;lcp[0]=0;for (int i=0;i<n;i++){int j=sa[rank[i]-1];//printf("LCP %d %d\n",i,j);if (h>0)h--;for (;i+h<n && j+h<n;h++)if (a[i+h]!=a[j+h])break;lcp[rank[i]-1]=h;}for (int i=0;i<=n;i++)f[i][0]=lcp[i];//printf("I  F  LCP  SA  RANK\n");//for (int i=0;i<=n;i++)printf("%d %d %d %d %d\n",i,f[i][0],lcp[i],sa[i],rank[i]);for (int j=1;(1<<j)<=n;j++)for (int i=1;i+(1<<j)-1<=n;i++)f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);/*for (int i=0;i<=n;i++){printf("CASE %d:",i);for (int j=0;i+(1<<j)-1<=n;j++)printf("%d ",f[i][j]);printf("\n");}*/while (m--){int x,y;scanf("%d%d",&x,&y);x--;y--;if (x==y){printf("%d\n",n-x);continue;}//printf("%d %d,\n",x,y);if (rank[x]>rank[y])swap(x,y);printf("%d\n",query(rank[x],rank[y]-1));}return 0;}


0 0
原创粉丝点击