CF1598G

讲真,有点谔谔。

首先考虑若 \(a+b=x\) 那么 \(|a|,|b|,|x|\) 满足什么样的关系。不妨设 \(|a|\ge |b|\),不难发现 \(|x|\ge |a|\ge |x|-1\)

那么分类讨论一下:

  • \(|a|=|x-1|\),则 \(|b|=|x-1|\)
  • \(|a|=|x|\),设 \(\operatorname{lcp}(a, x)=p\),则 \(|b|=x-p\)\(x-p-1\)

总体上只有 \(\mathcal O(n)\) 种可能情况。随便枚举。\(\rm lcp\) 不会 Z 函数,用的二分 hash。

然后判断 \(a+b=x\),高精也就 \(\mathcal O(n^2/\omega)\) 吧,还是得 hash,注意多随机取几个模数,正确率高的一批。我用了 6 个。跑过了。

不太好追溯思路其实,我反正是纯靠直觉。大概总结一下的话,就是限制非常非常强,有效状态很少,就可以考虑通过构造类的方法筛一筛。

#include <bits/stdc++.h>
#define pb emplace_back
#define fir first
#define sec second
using i64 = long long;
 
const int maxn = 7e5 + 5;
char s[maxn], t[maxn];
int n, m;
i64 a[6][maxn], valx[6], hash[maxn], pw[maxn], Hash[maxn], p, base, pwt[6][maxn];
std::vector<i64> mods;
std::mt19937 rd((unsigned)time(0));
 
i64 dec(i64 x, i64 y) {
	return (x - y) < 0 ? (x - y + p) : (x - y);
}
 
bool isprime(i64 x) {
	if(x < 2)
		return false;
	for(i64 i = 2;i * i <= x;++ i)
		if(!(x % i))
			return false;
	return true;
}
 
int lcp(int i) {
	int l = 0, r = std::min(n - i + 1, m), mid;
	while(l <= r) {
		mid = (l + r) >> 1;
		if(dec(hash[i + mid - 1], hash[i - 1] * pw[mid] % p) == Hash[mid])
			l = mid + 1;
		else
			r = mid - 1;
	}
	return r;
}
 
std::vector<i64> gethash(int l, int r) {
	std::vector<i64> A;
	for(int k = 0;k < 6;++ k)
		A.pb((a[k][r] - a[k][l - 1] * pwt[k][r - l + 1] % mods[k] + mods[k]) % mods[k]);
	return A;
}
 
void check(int l, int r, int x, int y){
	if(l > r||x > y||l < 1||r > n||x < 1||y > n)
		return ;
	std::vector<i64> A = gethash(l, r), B = gethash(x, y);
	for(int k = 0;k < 6;++ k)
		if((A[k] + B[k]) % mods[k] != valx[k])
			return ;
	printf("%d %d\n%d %d\n", l, r, x, y);
	exit(0);
	return ;
}
 
int main() {
	scanf("%s %s", s + 1, t + 1);
	n = strlen(s + 1);
	m = strlen(t + 1);
	pw[0] = 1;
	while((int)mods.size() <= 5) {
		i64 r = rd() % 998244353;
		if(isprime(r))
			mods.pb(r);
	}
	p = mods[rd() % 6];
	do {
		base = mods[rd() % 6];
	} while(base == p);
	for(int k = 0;k < 6;++ k) {
		pwt[k][0] = 1;
		for(int i = 1;i <= n||i <= m;++ i)
			pwt[k][i] = 10ll * pwt[k][i - 1] % mods[k];
		for(int i = 1;i <= n;++ i)
			a[k][i] = (10ll * a[k][i - 1] % mods[k] + (s[i] ^ '0')) % mods[k];
		for(int i = 1;i <= m;++ i)
			valx[k] = (10ll * valx[k] % mods[k] + (t[i] ^ '0')) % mods[k];
	}
	for(int i = 1;i <= n;++ i)
		hash[i] = (hash[i - 1] * base + s[i]) % p;
	for(int i = 1;i <= m;++ i)
		Hash[i] = (Hash[i - 1] * base + t[i]) % p;
	for(int i = 1;i <= n;++ i)
		pw[i] = pw[i - 1] * base % p;
	for(int i = 1;i <= n;++ i) {
		check(i, i + m - 2, i + m - 1, i + 2 * m - 3);
		int z = lcp(i);
		check(i, i + m - 1, i + m, i + m + (m - z) - 1);
		check(i, i + m - 1, i + m, i + m + (m - z - 1) - 1);
		check(i - (m - z), i - 1, i, i + m - 1);
		check(i - (m - z - 1), i - 1, i, i + m - 1);
	}
	return 0;
}
posted @ 2023-04-24 20:41  Modirant  阅读(35)  评论(1)    收藏  举报