51nod- 2619 三个好朋友(裸哈希)

37 篇文章 0 订阅
4 篇文章 0 订阅

51 nod-2619 三个好朋友

题目

首先有一个字符串 S,两个S拼接变成字符串 T,接着在 T 中插入一个字符变成了字符串 U。题目给出 U串,求是否存在原 S串。

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

分析

想暴力思路,对于每一位都假设是添加进去的,模拟删除之后两个字符串的左右是否相同。复杂度 O(n^2),肯定不行。

复杂度主要在比较字符串上,现在对整个字符串进行HASH,比较左右两部分时只比较HASH值,比较一次 O(1)。总的O(n)。

例:AGEDEF 哈希值(_hash数组存的东西):

A x 5 + G x 4 + E x 3 + D x 2 + E x + F Ax^5 + Gx^4 + Ex^3 + Dx^2 + Ex + F Ax5+Gx4+Ex3+Dx2+Ex+F

x 是自己指定的值。

注意取哈希值的时候,假设pos位是添加进去的,pos < mid。那么删除之后的右部分直接可以用预处理的哈希值。删除之后的左部分又被 pos 分了两部分,其中一部分要处理一下。

所以按照pos在左 中 右=分别讨论即可。
(坑:题目最后一组数据大于2e5)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll mod = 9999991;
const ull base = 23333;
const int N = 2e6 + 10;

ull _hash[N], p[N], pre;         // 用 ull 自然溢出
int n, cnt;
char str[N], ans[N];

inline ull get(int l, int r){
    return _hash[r] - _hash[l - 1] * p[r - l + 1];
}

inline int cal(int pos){
    ull l, r;
    int mid = (n >> 1) + 1;
    if(pos < mid){
        l = get(1, pos - 1) * p[mid - pos] + get(pos + 1, mid);
        r = get(mid + 1, n);
    }else if(pos == mid){
        l = get(1, mid - 1);
        r = get(mid + 1, n);
    }else{
        l = get(1, mid - 1);
        r = get(mid, pos - 1) * p[n - pos] + get(pos + 1, n);
    }
    if(l == r){
        if(pre == l)            //跟之前答案一样
            return 0;
        pre = l;
        if(pos <= mid){
            for(int i = mid + 1; i <= n; i++){
                ans[i - mid] = str[i];
            }
        }else{
            for(int i = 1; i < mid; i++){
                ans[i] = str[i];
            }
        }
        return 1;
    }
    return 0;
}

int main()
{
    scanf("%d%s", &n, str + 1);
    if(!(n&1)){
        puts("NOT POSSIBLE");
        return 0;
    }
    p[0] = 1;
    for (int i = 1; i <= n; i++){			//预处理 HASH值
        p[i] = p[i - 1] * base; 
        _hash[i] = _hash[i - 1] * base + str[i];
    }
    for(int i = 1; i <= n; i++){
        cnt += cal(i);
        if(cnt > 1)
            break;
    }
    if(!cnt){
        puts("NOT POSSIBLE");
    }else{
        puts(cnt == 1 ? ans + 1 : "NOT UNIQUE");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值