zoukankan      html  css  js  c++  java
  • 【POJ2774】Long Long Message(后缀数组)

    【POJ2774】Long Long Message(后缀数组)

    题面

    Vjudge

    Description

    Little cat在Byterland的首都读物理专业。这些天他收到了一条悲伤地信息:他的母亲生病了。担心买火车票花钱太多(Byterland是一个巨大的国家,因此他坐火车回家需要16小时),他决定只给母亲发短信。
    Little cat的家境并不富裕,因此他经常去营业厅查看自己发短信花了多少钱。昨天营业厅的电脑坏掉了,打印出两条很长的信息。机智的little cat很快发现:
    1.信息中所有的字符都是小写英文字母,没有标点和空格。
    2.所有的短信都被连在了一起——第i+1条短信直接接在第i条短信后面——这就是这两条信息如此长的原因。
    3.虽然他发的短信都被连在了一起,但由于电脑坏掉了,它们的左边或右边都可能会有许多冗余字符。
    例如:如果短信是"motheriloveyou",电脑打印出的每条信息都可能是 "hahamotheriloveyou", "motheriloveyoureally", "motheriloveyouornot", "bbbmotheriloveyouaaa",等等。
    4.因为这些乱七八糟的问题,little cat打印了两遍(所以有两条非常长的信息)。尽管原始的短信文本在两条信息中都一样,但两条信息在文本两侧的冗余字符都可能不一样。
    给出这两条很长的信息,输出little cat写下的原始短信文本的最长可能长度。
    背景:
    在Byterland,短信按照美元/字节的单位计价。这就是little cat想要知道原始文本最长可能长度的原因。
    为什么让你写一个程序?有四个原因:
    1.little cat这些天忙于他的物理课程。
    2.little cat不想透露他对母亲说了什么。
    3.POJ是个好网站。
    4.little cat想要从POJ那里挣点钱,并尝试说服他的母亲去医院

    Input

    两行两个由小写英文字母组成的字符串。字符串长度都不会超过100000

    Output

    一行一个整数,即little cat写下的原始文本的最长可能长度。

    Sample Input

    yeshowmuchiloveyoumydearmotherreallyicannotbelieveit
    yeaphowmuchiloveyoumydearmother

    Sample Output

    27

    题解

    把两个串接起来
    现在问题就可以转换成
    找两个后缀
    求他们的最长公共前缀的最大值

    这个最大值显然是一个(height)的值
    因为是要从两个串中各选出一个串
    所以要判断(SA[i])(SA[i-1])是否在两个不同的串中

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define MAX 220000
    inline int read()
    {
    	int x=0,t=1;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=-1,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return x*t;
    }
    char ch[MAX];
    int SA[MAX],x[MAX],y[MAX],t[MAX];
    int Rank[MAX],height[MAX],a[MAX];
    int n,n1,n2;
    bool cmp(int i,int j,int k){return y[i]==y[j]&&y[i+k]==y[j+k];}
    bool same(int i,int j){return ((i<=n1)&&(j<=n1))|((i>n1)&&(j>n1));}
    void GetSA()
    {
    	int m=30;
    	for(int i=1;i<=n;++i)t[x[i]=a[i]]++;
    	for(int i=1;i<=m;++i)t[i]+=t[i-1];
    	for(int i=n;i>=1;--i)SA[t[x[i]]--]=i;
    	for(int k=1;k<=n;k<<=1)
    	{
    		int p=0;
    		for(int i=0;i<=n;++i)y[i]=0;
    		for(int i=n-k+1;i<=n;++i)y[++p]=i;
    		for(int i=1;i<=n;++i)if(SA[i]>k)y[++p]=SA[i]-k;
    		for(int i=0;i<=m;++i)t[i]=0;
    		for(int i=1;i<=n;++i)t[x[y[i]]]++;
    		for(int i=1;i<=m;++i)t[i]+=t[i-1];
    		for(int i=n;i>=1;--i)SA[t[x[y[i]]]--]=y[i];
    		swap(x,y);
    		x[SA[1]]=p=1;
    		for(int i=2;i<=n;++i)x[SA[i]]=cmp(SA[i],SA[i-1],k)?p:++p;
    		if(p>=n)break;
    		m=p;
    	}
    	for(int i=1;i<=n;++i)Rank[SA[i]]=i;
    	for(int i=1,j=0;i<=n;++i)
    	{
    		if(j)j--;
    		while(a[i+j]==a[SA[Rank[i]-1]+j])++j;
    		height[Rank[i]]=j;
    	}
    }
    int main()
    {
    	scanf("%s",ch+1);
    	n=n1=strlen(ch+1);
    	for(int i=1;i<=n1;++i)a[i]=ch[i]-96;
    	scanf("%s",ch+1);
    	for(int i=1,l=strlen(ch+1);i<=l;++i)a[++n]=ch[i]-96;
    	n2=n-n1;
    	GetSA();
    	int ans=0;
    	for(int i=2;i<=n;++i)
    		if(!same(SA[i],SA[i-1]))
    			ans=max(ans,height[i]);
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    layui 参照赋值的两种方式
    c笔记
    Linux操作系统笔记
    make笔记
    Gcc如何知道文件类型。
    #include <xxx.h>和#include "xxx.h"的区别
    GCC编译流程
    c++ Socket客户端和服务端示例版本三(多线程版本)
    c++ Socket客户端和服务端示例版本二
    c++ Socket客户端和服务端示例版本一
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8335761.html
Copyright © 2011-2022 走看看