• #2823. 「BalticOI 2014 Day 1」三个朋友 题解


    【杂言】:

    前置知识为(Hash) , 我的 理解


    【题目描述】:

    给定一个字符串(S),先将字符串(S)复制一次(变成双倍快乐),得到字符串(T),然后在(T)中插入一个字符,得到字符串(U)

    给出字符串(U),重新构造出字符串(S)。(字符串(S)的长度 (leq 2e7+1)


    【思路】:

    首先 , 看到构造字符串, 我们就想到了字符串匹配(然后你就想到了(KMP)) , 然后你就想到了用哈希干掉这道题(请忽略我看了题目标签,谢谢合作)

    然后, 我们再次发现,对于得到的新的字符串,一定不会是偶数,因为(copy)过后,又加了1,也就是长度应该为(2k+1)(其中(k)为字符串(S)的长度) 。那么就找出一个不可能的条件

    再然后 ,没有一眼结论了,那么好, 我们换思路考虑一下 ,我们很自然的可以想到,我只需要枚举去掉一个字符之后,判断一下,两边是否相等,如果相等,那么也就必然能够表示出来


    同时我们也出现一个疑惑 , 那就是如何判断一下形成字符串(S)是否是唯一的呢? ,很麻烦 ,我们需要继续分类,然后看一下是否还能分(为之后的优化打下坚实的基础)

    联想一下哈希, 我们发现 ,我们预处理出前缀的哈希值 , 我们还是枚举多余字符的位置,同时,我们根据其位置与 (frac{n}{2})(frac{n}{2} + 1)的关系,来判断并求解出前后两个字符串的哈希值(由于这是一个(copy),所以只需要比较第(frac{n}{2})(frac{n}{2}+1)即可) 。

    我们假设 (x)为前半部分(hash)值,(y)为后半部分(hash)值 ,

    当我们枚举的时候,我们必然是要看一下删除完的字符串的(Hash)值, 那么其中原来的(Hash)怎么处理呢?(也就是刚刚我们假设的(x)),我们来look一下这个图

    ,


    当枚举到左边的那一个字符时,

    [x = sumlimits_{k=1} ^ {i-1} h(k) + sumlimits_{l = i+1} ^ {frac{n}{2}} h(l) ]

    [h(sumlimits_{k=i+1}^{frac{n}{2}+1}) = h(frac{n}{2}+1) - h(i) imes power_{frac{n}{2}+1-i} ]

    同时, (1……i-1)(Hash)值为 : (hash_{i-1}) ,由于要和(i+1,i+2 , …… frac{n}{2} +1)组成一个部分,也就是要对齐,所以,
    应该乘以一个(power_{frac{n}{2} - i + 1}) ,其中(frac{n}{2} - i +1)表示的就是(i+1,i+2,…… , frac{n}{2} +1)的长度。

    枚举在左边的处理完了,接下来看一下枚举右边的,这时候左边是完全不需要动的, 我们只需要动一下后面,让他们对齐,


    当枚举到左边的那一个字符时,

    [y = hash_{i-1} - hash_{frac{n}{2}} imes power_{i - frac{n}{2} -1} ]

    这个式子很明显,比上一个式子简单,且考虑的东西明显要少。
    (i-1-frac{n}{2})表示的是有半部分从开始到(i-1)的长度,
    其开始位置为$frac{n}{2} +1 $ ,(n-i)是后面的的长度,为了让他们对齐, 所以要乘以一个(power_{n-i})


    然后我们可以考虑一下我们的问题了, 我们的唯一解了。 其实也是十分的简单, 我们只需要在进行搜索到的时候一个的时候,记录一下第一个可以得到字符串(S)的位置,同时在进行枚举,看一下是否还有其他的方法可以形成另一个字符串(s_{1}),然后如果重复,就输出应该输出的东西就好了


    (code)】:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <map>
    #include <stack>
    #define int unsigned long long
    using namespace std ;
    const int kmaxn = 2e7 + 10 ;
    const int p1 = 1e3 + 7 ;
    const int p2 = 1331 ;
    const int mod1 = 10003 ;
    const int mod2 = 13331 ;
    inline int read()
    {
    	int x = 0 , f = 1 ; char ch = getchar() ;
    	while(!isdigit(ch)) { if(ch == '-') f = - 1 ; ch = getchar() ; }
    	while( isdigit(ch)) { x = x * 10 + ch - '0' ; ch = getchar() ; }
    	return x * f ;
    }
    int n , x , y , ans , tot , p;
    bool flag ; 
    char s[kmaxn] ;
    int sum[kmaxn];
    int power[kmaxn] ;
    void prepare() //预处理 ,艹,这是板子。 
    {
    	power[0] = 1 ;
    	for(int i = 1 ; i <= n ; i++) //预处理出p2的n次方 
    	{
    		power[i] = power[i - 1] * p2 ; //直接让其无符号整数自动截取来完成取模,省去耗时间复杂度较高的模运算 
    	}
    	for(int i = 1 ; i <= n ; i++) //预处理出字符串的哈希值 
    	{
    		sum[i] = sum[i - 1] * p2 + s[i] - 'A' + 1 ;
    	}
    	
    }
    void work()
    {
    	for(int i = 1 ; i <= n ; i++)
    	{
    		if(i <= n/2)
    		{
    			x = sum[n / 2 + 1] - sum[i] * power[n / 2 - i + 1] + sum[i - 1] * power[n / 2 - i + 1];
    		}
    		else 
    		{
    			x = sum[n / 2] ;
    		}
    		if(i <= n /2 + 1) 
    		{
    			y = sum[n] - sum[n / 2 + 1] * power[n / 2] ;
    		}
    		else 
    		{
    			y = (sum[i - 1] - sum[n / 2] * power[i - n / 2 - 1]) * power[n - i] + sum[n] - sum[i] * power[n - i] ;
    		}
    		if(x == y) 
    		{
    			if(flag && ans != x) //形成的字符串不唯一 
    			{
    				printf("NOT UNIQUE
    ") ;
    				return ;
    			}
    			flag = 1 , ans = x , p = i ;
    		}
    	}
    	if(!flag)
    	{
    		printf("NOT POSSIBLE
    ") ;
    		return ;
    	}
    	for(int i = 1 ; tot < n / 2 ; i ++)
    	{
    		if(i != p )
    		{
    			printf("%c" , s[i]) ;
    			tot ++ ;
    		}
    	}
    	printf("
    ") ;
    	return ;
    }
    signed main()
    {
    	n = read() ;
    	scanf("%s" , s+1) ;
    	if(n % 2 == 0) 
    	{
    		printf("NOT POSSIBLE
    ") ;
    		return 0 ;
    	} //如果是偶数, 那么删去一个字符会形成奇数 ,但是 copy的必是偶数 , 故 不可能有解
    	prepare() ; 
    	work() ; 
    	return 0 ; 
    } 
    
  • 相关阅读:
    虚拟化(五):vsphere高可用群集与容错(存储DRS是一种可用于将多个数据存储作为单个数据存储群集进行管理的功能)
    vmware 桌面虚拟化 horizon view 介绍(使用微软的RDP协议或vmware 专有的PCoIP协议,连接到虚拟桌面,并且可以使用本地的USB设备、本地存储)
    Delphi之萝莉调教篇
    编写自定义PE结构的程序(如何手写一个PE,高级编译器都是编译好的PE头部,例如MASM,TASM等,NASM,FASM是低级编译器.可以自定义结构)
    localStore的storage事件
    对称密码体制和非对称密码体制
    Span<T>和ValueTuple<T>性能是.Net Core非常关键的特性
    分布式高并发下Actor模型
    公众号及H5支付
    BIOS(Basic Input/Output System)是基本输入输出系统的简称
  • 原文地址:https://www.cnblogs.com/Zmonarch/p/14213299.html
Copyright © 2020-2023  润新知