首页 > 其他分享 >【2022牛客多校】第五场 Crazy Thursday 二分+字符串哈希

【2022牛客多校】第五场 Crazy Thursday 二分+字符串哈希

时间:2022-08-20 16:25:42浏览次数:98  
标签:Crazy int 第五场 mid prec 哈希 ans rh 回文

https://ac.nowcoder.com/acm/contest/33190/G

题意
给你一个长为n的字符串s,求s中分别以'k'、'f'、'c'结尾的回文串数量

\(n <= 5e5\)

思路
首先暴力枚举区间端点加判断,为 \(O(n^3)\) ,肯定会超时

注意到对于每个位置的字符,可以找到以它为中心的回文串的最大长度,那么(仍以这个字符为中心的)最大串内部的串也都是回文串

那么考虑二分以每个字符为中心的串的回文最大半径,找到最大回文半径后可以利用区间加算出答案

此外还需注意回文串可能以某个字符为中心,长度为奇数;也可能以某两个相同的字符为中心,长度为偶数。这里需要分情况讨论

还有一个问题,二分的check如果是 \(O(n)\) 的,仍然会超时(亲身实践

那么需要用到更快的 \(O(1)\) 的check方式——字符串哈希

细节见代码

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define pb push_back
using namespace std;
const int N = 5e5+10, seed = 31;
int t, n, m;
char s[N];
int prek[N], pref[N], prec[N];
ll ansk, ansf, ansc;
ull h[N], rh[N], base[N];

inline ull Hash(int l, int r) {
	return h[r] - h[l - 1] * base[r - l + 1];
}

inline ull rHash(int l, int r) {
	return rh[l] - rh[r + 1] * base[r - l + 1];
}

inline bool check(int x, int r) {
	return Hash(x - r + 1, x) == rHash(x, x + r - 1);
}

inline bool check2(int x, int r) {
	return Hash(x - r + 1, x) == rHash(x + 1, x + r);
}

void init() {
	base[0] = 1;
	for (int i = 1; i <= n; i++) base[i] = base[i - 1] * seed;
	h[0] = 0;
	for (int i = 1; i <= n; i++) {
		h[i] = h[i - 1] * seed + s[i] - 'a';
	}
	rh[n + 1] = 0;
	for (int i = n; i >= 1; i--) {
		rh[i] = rh[i + 1] * seed + s[i] - 'a';
	}
}

void solve() {
	//ji
	for (int i = 1; i <= n; i++) {
		int l = 1, r = min(i, n - i + 1), mid, ans;
		while (l <= r){
			mid = (l + r) >> 1;
			if (check(i, mid)) {
				l = mid + 1;
				ans = mid;
			}
			else r = mid - 1;
		}
		ansk += prek[ans + i - 1] - prek[i - 1];
		ansf += pref[ans + i - 1] - pref[i - 1];
		ansc += prec[ans + i - 1] - prec[i - 1];
	}
	//ou
	for (int i = 1; i < n; i++) {
		if (s[i] != s[i + 1]) continue;
		int l = 1, r = min(i, n - i), mid, ans = -1;
		while (l <= r){
			mid = (l + r) >> 1;
			if (check2(i, mid)) {
				l = mid + 1;
				ans = mid;
			}
			else r = mid - 1;
		}
		if(ans == -1) continue;
		ansk += prek[ans + i] - prek[i];
		ansf += pref[ans + i] - pref[i];
		ansc += prec[ans + i] - prec[i];
	}
}

int main(){
    cin >> n;
	scanf("%s", s + 1);
	init();
	for (int i = 1; i <= n; i++) {
		prek[i] = prek[i-1] + (s[i] == 'k');
		pref[i] = pref[i-1] + (s[i] == 'f');
		prec[i] = prec[i-1] + (s[i] == 'c');
	}
	solve();
	printf("%lld %lld %lld\n", ansk, ansf, ansc);
    system("pause");
    return 0;
}

标签:Crazy,int,第五场,mid,prec,哈希,ans,rh,回文
From: https://www.cnblogs.com/re0acm/p/16607954.html

相关文章

  • codeforces963D. Frequency of String【哈希】
    我的腿让我停下,可是我的心却不许我这么做今天又是为了明知多半不可能的事情奔波一早,一天里,出了很多丑,犯了很多错,见了很多人,有了很多意想不到的收获,我选择了我的生存方式......
  • 哈希
    字符串哈希哈希是一种高效判断字符串相等的算法,准确来说是子串,因为预处理需要\(O(n)\),自然是多次使用才划算常见的哈希式是\(\suma_ibase^i(mod\mod)\)即选取一个......
  • 哈希类型,列表类型,集合类型,有序集合类型,慢查询,pipline与事务,发布订阅,Bitmap,HyperLogLog
    1API的使用1.1哈希类型###1---hget,hset,hdelhgetkeyfield#获取hashkey对应的field的value时间复杂度为o(1)hsetkeyfieldvalue#设置hashkey对应的field......
  • 哈希表4:两数之和(1)
    本题如下:(链接:https://leetcode.cn/problems/two-sum/)题目:给定一个整数数组nums 和一个整数目标值target,请你在该数组中找出和为目标值target 的那 两个 整数,并返......
  • Redis---hash哈希散列
    1.前言Redishash(哈希散列)是由字符类型的field(字段)和value组成的哈希映射表结构(也称散列表),它非常类似于表格结构。在hash类型中,field与value一一对应,且不允许重......
  • 子数组异或和(前缀和、哈希)
    题意给定一个长度为\(n\)的整数数组\(a_1,a_2,\dots,a_n\)。请你统计一共有多少个数组\(a\)的非空连续子数组能够同时满足以下所有条件:该连续子数组的长度为偶数。......
  • 哈希表2:两个数组的交集(349)
    本题如下:(链接:https://leetcode.cn/problems/intersection-of-two-arrays/submissions/)题目:给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一......
  • 道长的算法笔记:经典哈希表问题
    (一)哈希表简述Waiting...(二)使用哈希表优化复杂度(2.1)两数之和Waiting...(2.2)子数组异或和#include<bits/stdc++.h>#include<algorithm>usingnamespace......