• jzoj 3189. 【GDOI2013模拟8】解密


    Description

    Mirko要解一段加密文,但他只知道某一个句子是原文的一部分。你的任务是要在密文中找到第一个对应这个句子的地方。

    文段是通过用某个单词(可能和原文一样的单词)替换原始文段每一个单词来加密的。如果某些单词在原文出现一次以上,就会使用相同的替换单词来替换。没有两个不同的单词使用相同的替换单词。

    单词是通过空格隔开的小写字母序列。句子是连续单词的序列。

    Input

    第一行输入密文,这段文段不会有超过10^6个字符,每个单词之间只会有一个空格字符,行末处输入不是文段的一部分。

    接下来一行输入出现在原文中的句子,这个句子就是我们要在密文中要找到的句子。句子不会超过10^6个字符,而且符合上面所描述的格式。

    Output

    输出一行,包括第一个对应原始文段句子的第一个单词的位置。

    Sample Input

    输入1:

    a a a b c d a b c $

    x y $

    输入2:

    xyz abc abc xyz $

    abc abc $

    输入3:

    a b c x c z z a b c $

    prvi dr prvi tr tr x $

    Sample Output

    输出1:

    3

    输出2:

    2

    输出3:

    3

    Data Constraint

    N<=1000000

    Solution

    这题我™改了好久(一直WA80,后发现自己KMP打挂了(竟然还有80…数据是有多水))
    我们发现,这题就是问母串中是否有与子串相形似的串,有则输出位置开头,否则return 0。
    我们可以神奇地发现,如果串相匹配的话,那么当中的任意一个字母与前面与其相同的字母的间隔是一样的。(PS:如果母串中的前面字母的位置跳出了匹配位置的话也算匹配)
    所以我们按照这个来hash一波,然后就可以用KMP来搞一搞了!!!
    哈哈,这方法,真的是太牛逼了!!!

    Code

    #include<cstdio>
    #include<cstring>
    #define ctu while (c<'a' || c>'z') c=getchar()
    #define gc getchar
    #define N 1000010
    #define mo 838379
    #define MO 13578987531
    #define ll long long
    using namespace std;
    int a[N],b[N],bf[N],tot=0,cnt=0;
    int nx[N],pl[mo+10];
    ll x,x1,h[mo+10]; char c;
    
    int main()
    {
    	freopen("secret.in","r",stdin);
    //	freopen("secret.out","w",stdout);
    	c=gc();ctu;
    	while (c!='$')
    	{
    		x=0;
    		while (c>='a' && c<='z')
    			x=(x*29+(c-'a'+1))%MO,c=gc();
    		x1=x%mo;
    		while (h[x1])
    		{
    			if (h[x1]==x)
    			{
    				a[++tot]=tot-pl[x1];
    				pl[x1]=tot;break;
    			}
    			x1=(x1+1)%mo;
    		}
    		if (!h[x1])
    		{
    			a[++tot]=0;
    			h[x1]=x,pl[x1]=tot;
    		}
    		c=gc();
    	}
    	memset(h,0,sizeof(h));
    	memset(pl,0,sizeof(pl));
    	c=gc();ctu;
    	while (c!='$')
    	{
    		x=0;
    		while (c>='a' && c<='z')
    			x=(x*29+(c-'a'+1))%MO,c=gc();
    		x1=x%mo;cnt++;
    		while (h[x1])
    		{
    			if (h[x1]==x)
    			{
    				b[cnt]=cnt-pl[x1];
    				pl[x1]=cnt;break;
    			}
    			x1=(x1+1)%mo;
    		}
    		if (!h[x1])
    		{
    			b[cnt]=0;
    			h[x1]=x,pl[x1]=cnt;
    		}
    		c=gc();
    	}
    	nx[1]=0;
    	for (int i=2,j=0;i<=cnt;i++)
    	{
    		while (j>0 && b[i]!=b[j+1]) j=nx[j];
    		if (b[i]==b[j+1]) j++;
    		nx[i]=j;
    	}
    	for (int i=1,j=0;i<=tot;i++)
    	{
    		while (j>0 && (a[i]!=b[j+1] && (b[j+1]>0 || j-a[i]>=0))) j=nx[j];
    		if (a[i]==b[j+1] || (b[j+1]==0 && j-a[i]<0)) j++;
    		if (j==cnt) return 0&printf("%d
    ",i-cnt+1);
    	}
    	puts("0");
    	return 0;
    }
    
    转载需注明出处。
  • 相关阅读:
    ajax代码及简单封装
    web开发中不同设备浏览器的区分
    JS实现带复选框的下拉菜单
    常用浏览器的编码设置
    PHP实现实现数字补零格式化
    Linux杂碎2/SHELL
    OS
    Linux sudoers
    代理缓存服务器squid
    es6
  • 原文地址:https://www.cnblogs.com/jz929/p/11817534.html
Copyright © 2020-2023  润新知