【字符串】字符串哈希

题目: https://www.acwing.com/problem/content/4699/

代码:

#include<bits/stdc++.h>
 
using namespace std;
#define int long long

const int N = 2e6+5;
const int Mod = 131;

string s;
int f1[N],f2[N],p[N];
int ans,l,r,mid;

int Hash1(int i,int j){//正字符串的哈希值
    return (f1[j]-f1[i-1]*p[j-i+1]);
}

int Hash2(int i,int j){//反字符串的哈希值
    return (f2[i]-f2[j+1]*p[j-i+1]);
}

void init(){
    p[0]=1;//p^0为1
    for(int i=1;i<=N-1;i++)
        p[i]=p[i-1]*131;//P进制的位值
}

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

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	init();
	ans=0;
    cin>>s;
    s=' '+s;
    int len=s.size();
    
    f2[len+1]=0;//初始化要注意,不然的话容易GG
    for(int i=1;i<=len;i++){
    	f1[i]=f1[i-1]*Mod+(s[i]-'a'+1);//前缀和
    } 
    for(int i=len;i>=1;i--){
    	f2[i]=f2[i+1]*Mod+(s[i]-'a'+1);//后缀和
    }
    for(int i=1;i<=len;i++){
        l=0,r=min(i-1,len-i);//二分枚举长度为奇数的字符串 记住这里l一定要为0,不然的话,你会发现最后一个数据会卡死你.
        while(l<r){
            mid=l+r+1>>1;
            if(Hash1(i-mid,i-1)==Hash2(i+1,i+mid)){//如果这是一个回文串的话
            	l=mid;
            }
            else{
            	r=mid-1;
            } 
        }
        ans=max(l<<1|1,ans);//算出最大长度
        l=0,r=min(i-1,len-i+1);//偶数字符串
        while(l<r){
            mid=l+r+1>>1;
            if(Hash1(i-mid,i-1)==Hash2(i,i+mid-1)){//check判断
            	l=mid;
            }
            else{
            	r=mid-1;
            }
        }
        ans=max(l<<1,ans);//偶数字符串只需要*2
    }
    cout<<ans<<"\n";
	
	
	return 0;	
 
}

练习:

https://atcoder.jp/contests/abc284/tasks/abc284_f

字符串双哈希模板: 

std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());

bool isprime(int n) {
    if (n <= 1) return false;
    for (int i = 2; i * i <= n; i++)
        if (n % i == 0)
            return false;
    return true;
}
int findPrime(int n) {
    while (!isprime(n))
        n++;
    return n;
}

template<int N>
struct StringHash {
    static array<int, N> mod;
    static array<int, N> base;
    vector<array<int, N>> p, h;
    StringHash() = default;
    StringHash(const string& s) {
        int n = s.size();
        p.resize(n);
        h.resize(n);
        fill(p[0].begin(), p[0].end(), 1);
        fill(h[0].begin(), h[0].end(), 1);
        for (int i = 0; i < n; i++)
            for (int j = 0; j < N; j++) {
                p[i][j] = 1ll * (i == 0 ? 1ll : p[i - 1][j]) * base[j] % mod[j];
                h[i][j] = (1ll * (i == 0 ? 0ll : h[i - 1][j]) * base[j] + s[i]) % mod[j];
            }
    }
    array<int, N> query(int l, int r) {
        assert(r >= l - 1);
        array<int, N> ans{};
        if (l > r) return {0, 0};
        for (int i = 0; i < N; i++) {
            ans[i] = (h[r][i] - 1ll * (l == 0 ? 0ll : h[l - 1][i]) * (r - l + 1 == 0 ? 1ll : p[r - l][i]) % mod[i] + mod[i]) % mod[i];
        }
        return ans;
    }
};

constexpr int HN = 2;
template<>
array<int, 2> StringHash<HN>::mod =
        {findPrime(rng() % 900000000 + 100000000),
         findPrime(rng() % 900000000 + 100000000)};
template<>
array<int, 2> StringHash<HN>::base {13331, 131};
using Hashing = StringHash<HN>;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值