AT4163 [ARC099D] Eating Symbols Hard

AT4163 [ARC099D] Eating Symbols Hard

手玩数据,不难发现,这几种操作类似于子串哈希的过程。

区间操作序列判断相同更坚定了我们的想法,哈希解决问题。

考虑维护前缀哈希,一个区间 [ l , r ] [l,r] [l,r] 的哈希值,应该是 [ 1 , r ] [1,r] [1,r] 的哈希值,减去 [ 1 , l − 1 ] [1,l-1] [1,l1] 移位后的哈希值,移位顺便维护一下即可。

最后双或三哈希判断,开桶记录个数即可,时间复杂度 O ( n ) \mathcal O(n) O(n)

#include<bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

#define ha putchar(' ')
#define he putchar('\n')

inline int read()
{
	int x = 0, f = 1;
	char c = getchar();
	while (c < '0' || c > '9')
	{
		if (c == '-')
			f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
		x = x * 10 + c - '0', c = getchar();
	return x * f;
}

inline void write(ll x)
{
	if(x < 0)
	{
		putchar('-');
		x = -x;
	}
	if(x > 9)
		write(x / 10);
	putchar(x % 10 + '0');
}

const int _ = 250010 * 2;

const ll bs1 = 819, Bs1 = 783725420, md1 = 998244353, bs2 = 1989, Bs2 = 227249785, md2 = 999999607, bs3 = 1998, Bs3 = 582062931, md3 = 999967099;

ll n, As, pos[_];

ull r1, r2, r3, p1[_], P1[_], p2[_], P2[_], p3[_], P3[_], hs1[_], hs2[_], hs3[_];

char s[_];

map<tuple<int, int, int>, int> mp;

signed main()
{
	n = read();
	scanf("%s", s + 1);
	p1[0] = P1[0] = p2[0] = P2[0] = p3[0] = P3[0] = 1;
	for(int i = 1; i <= n * 2; ++i)
	{
		p1[i] = p1[i - 1] * bs1 % md1;
		P1[i] = P1[i - 1] * Bs1 % md1;
		p2[i] = p2[i - 1] * bs2 % md2;
		P2[i] = P2[i - 1] * Bs2 % md2;
		p3[i] = p3[i - 1] * bs3 % md3;
		P3[i] = P3[i - 1] * Bs3 % md3;
	}
	pos[0] = n;
	for(int i = 1; i <= n; ++i)
	{
		pos[i] = pos[i - 1];
		if(s[i] == '>') pos[i] = pos[i - 1] + 1;
		if(s[i] == '<') pos[i] = pos[i - 1] - 1;
		if(s[i] == '+')
		{
			r1 = (r1 + p1[pos[i]]) % md1;
			r2 = (r2 + p2[pos[i]]) % md2;
			r3 = (r3 + p3[pos[i]]) % md3;
		}
		if(s[i] == '-')
		{
			r1 = (r1 + md1 - p1[pos[i]]) % md1;
			r2 = (r2 + md2 - p2[pos[i]]) % md2;
			r3 = (r3 + md3 - p3[pos[i]]) % md3;
		}
		hs1[i] = r1, hs2[i] = r2, hs3[i] = r3;
	}
	for(int i = n - 1; i >= 0; --i)
	{
		mp[{hs1[i + 1], hs2[i + 1], hs3[i + 1]}]++;
		ull k1 = (hs1[i] + (r1 * ((pos[i] <= n) ? P1[n - pos[i]] : p1[pos[i] - n]) % md1)) % md1;
		ull k2 = (hs2[i] + (r2 * ((pos[i] <= n) ? P2[n - pos[i]] : p2[pos[i] - n]) % md2)) % md2;
		ull k3 = (hs3[i] + (r3 * ((pos[i] <= n) ? P3[n - pos[i]] : p3[pos[i] - n]) % md3)) % md3;
//		cout << k1 << " " << k2 << "\n";
		As += mp[{k1, k2, k3}];
	}
	write(As);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值