• 【题解】Bzoj3916


    字符串(Hash).

    笔者实在太菜了,到现在还没有熟练掌握(Hash),就来这里写一篇学习笔记。

    (Description)

    有三个好朋友喜欢在一起玩游戏,(A)君写下一个字符串(S,B)君将其复制一遍得到(T,C)君在T的任意位置(包括首尾)插入一个字符得到(U).现在你得到了(U),请你找出(S.)

    (Input)

    第一行一个数(N),表示(U)的长度.

    第二行一个字符串(U),保证(U)由大写字母组成

    (Output)

    输出一行,若S不存在,输出"NOT POSSIBLE".若(S)不唯一,输出"NOT UNIQUE".否则输出(S.)

    字符串(Hash),可以快速做到字符串匹配。比如,从一个字符串中选择两个子串进行匹配,还是要(Hash)的。

    (Hash)是一种随机算法。我们设计一个(Hash)函数:

    设字符串(C=c_1c_2...c_n)(K)为字符串的长度(前(K)个)

    选择两个数(b,h),满足(b<h,b)(h)互质。

    我们有:

    (Hash(C,K)=Hash(C,K-1)*b+c_k)

    所以,我们的复杂度瓶颈就在处理(b)上了。

    对上面的函数拆开来写,就是:

    (x=m-1),

    (Hash(C)=(c_1*b^x+...+c_m*1) mod h)

    预处理(b)的次幂,递推即可。

    考虑一下(Hash)冲突的问题。

    我们前面取了一个模数(h=Mod)对吧。后面我写成(Mod).

    显然,对于任意串的(Hash)值一定是模(Mod)意义下剩余系中的一个,可以认为在区间([0,Mod-1])中随机分布。

    考虑几个串不相等。

    对于第一个串,有(frac{Mod-1}{Mod})的概率。

    如果第二个要和第一个不相等,就只有(frac{Mod-2}{Mod})的概率。

    以此类推,所有串不相等的概率为:

    (frac{Mod-1}{Mod}*frac{Mod-2}{Mod}*...*frac{Mod-i+1}{Mod})

    (i)是子串数(枚举)。

    当我们把模数(1e9),字符串数达到(1e5)的时候,不冲突的概率为:

    (0.006737160911819992)

    在这么大的数据下,显然冲突的概率非常高。如何提高它不冲突的概率?

    我们选择模数的时候,发现模数越大,冲突概率越小。那我们就可以利用(unsigned long long),自然溢出即可。

    还可以双(Hash),然而笔者太菜,不会,就先不说了,其实就是在就算一遍(Hash)后再计算几遍,只有(Hash)值全部相等才算匹配成功。

    考虑单(Hash)

    这道题,我们的思路就是,枚举断点,然后计算前后两个子串的(Hash)是否匹配。

    取一段子串的(Hash)值时,记住:

    当其起点为(i),终点为(j)时(子串),

    (Hash=H[r]-H[l-1]*power[r-l+1])

    其中(H)数组是计算主串(Hash)时计算出来的。

    这道题注意一下细节即可。判重的时候,如果与前面有一样的答案,算一个。除非是答案中的字符串不同,才算多重答案。

    (Code:)

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<string>
    using namespace std;
    typedef unsigned long long ull;
    const int B=2333333;
    const int H=1e9+9;
    int n,vis,L;
    ull power[2000010],h[2000010],last;
    char s[2000010],a[2000010];
    ull Get(int l,int r){return h[r]-h[l-1]*power[r-l+1];}
    bool check(int pos){
    	ull x,y,z;
    	int flag=0;
    	if(pos<L){
    		x=Get(1,pos-1)*power[L-pos]+Get(pos+1,L);
    		y=Get(L+1,n);
    	}
    	else if(pos>L){
    		x=Get(1,L-1);
    		y=Get(L,pos-1)*power[n-pos]+Get(pos+1,n);
    	}
    	else if(pos==L){
    		x=Get(1,L-1);
    		y=Get(L+1,n);
    	}
    	if(x==y){
    		if(x==last)return 0;
    		last=x;
    		int top=0;
    		if(pos<=L)
    			for(int i=L+1;i<=n;++i)
    				a[++top]=s[i];
    		else
    			for(int i=1;i<=L-1;++i)
    				a[++top]=s[i];
    		return true;
    	}
    	return 0;
    }
    int main(){
    	scanf("%d",&n);
    	scanf("%s",s+1);
    	power[0]=1;
    	if(n%2==0){
    		printf("NOT POSSIBLE
    ");
    		return 0;
    	}
    	for(int i=1;i<=n;++i)
    		power[i]=power[i-1]*B;
    	for(int i=1;i<=n;++i)
    		h[i]=h[i-1]*B+s[i];
    	L=(n>>1)+1;
    	for(int i=1;i<=n;++i){
    		vis+=check(i);
    		if(vis>1)break;
    	}
    	if(!vis){
    		printf("NOT POSSIBLE
    ");
    		return 0;
    	}
    	else if(vis>1){
    		printf("NOT UNIQUE
    ");
    		return 0;	
    	}
    	else puts(a+1);
    	return 0;
    } 
    
  • 相关阅读:
    多个装饰器装饰一个函数
    DRF 里面DestroyAPIView实例
    ERROR: Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-install-e7q1vcuk/mysqlclient/解决办法!
    python3 协程爬取两张妹子图
    python3 协程简单运用爬取两张妹子图
    gevent 简单运用
    D
    C
    B
    javascript cookie
  • 原文地址:https://www.cnblogs.com/h-lka/p/11317632.html
Copyright © 2020-2023  润新知