题解 P6739 【[BalticOI 2014 Day1] Three Friends】

题目传送门

由于本蒟蒻太菜,想不到别的做法,所以看到题的第一反应是hash; 虽然hash确实在码量上比较多,但是它好写思维难度比较低;

分析

假设一个字符串的前缀哈希值记为 h[i],进制为 base,那么显然 h[i] = h[i-1] \times base + s[i].

记 p[i] 为 base 的 i 次方,那么我们可以 O(1) 得到一个字串的哈希值。

 

inline unsigned long long check(int l,int r){
    return h[r]-h[l-1]*pre[r-l+1];
}

 

 

 其中,乘以 p[r-l+1] 相当于左移了 r-l+1 位。

同样,我们可以 O(1) 得到字串中删除一个字符后的hash值。

inline unsigned long long sum(int l,int r,int k){
    return check(l,k-1)*pre[r-k]+check(k+1,r);
}

 

 

 枚举每一个位置,剩下的应是两个相同的字符串,根据hash值判断一下。

上完整代码


 

#include<cstdio>
#include<iostream>
#include"cstring"
using namespace std;
#define maxn 2000002
string a,b,c,d;
int n,mid,l1,l2,h[maxn],pre[maxn];
char s[maxn];
int ans;
inline unsigned long long check(int l,int r){
    return h[r]-h[l-1]*pre[r-l+1];
}
inline unsigned long long sum(int l,int r,int k){
    return check(l,k-1)*pre[r-k]+check(k+1,r);
}
inline void out(){
    if(!ans)printf("NOT POSSIBLE");
    else if(ans==1||c==d)cout<<(c.size()?c:d);
    else printf("NOT UNIQUE");
}
inline void work(){
    l1=check(mid+1,n);
    for(int i=mid+1;i<=n;i++)a.push_back(s[i]);
    for(int i=1;i<=mid;i++){
        l2=sum(1,mid,i);
        if(l1==l2){
            ans++;
            c=a;
            break;
        }
    }
    l2=check(1,mid-1);
    for(int i=1;i<mid;i++)b.push_back(s[i]);
    for(int i=mid;i<=n;i++){
        l1=sum(mid,n,i);
        if(l1==l2){
            ans++;
            d=b;
            break;
        }
    }
    out();
}
int main(){
    scanf("%d%s",&n,s+1);
    mid=(n+1)>>1;
    if(!(n&1))return printf("NOT POSSIBLE"),0;
    pre[0]=1;
    for(int i=1;i<=n;i++){
        pre[i]=pre[i-1]*733;
        h[i]=h[i-1]*733+(s[i]-'A'+1);
    }
    work();
    return 0;
}

 

posted @ 2020-08-16 16:52  Nakiri_Ayame_suki  阅读(381)  评论(0编辑  收藏  举报