【省内训练2018-12-23】String

本文深入探讨了字符串匹配算法中的核心概念,特别是在处理含有特定字符的字符串时如何进行有效匹配。文章详细分析了不同情况下字符串匹配的策略,包括无问号情况下的匹配规则,以及如何通过枚举和组合数计算来解决复杂匹配问题。此外,还提供了时间复杂度分析和代码实现,为读者提供了一个全面理解字符串匹配算法的视角。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【思路要点】

  • 考虑无问号的情况,分为两种:
    111S=TS=TS=T ,那么 AAABBB 取任意字符串均可,贡献为 arbitrary=∑i=1N2i∑j=1N2jarbitrary=\sum_{i=1}^{N}2^i\sum_{j=1}^{N}2^jarbitrary=i=1N2ij=1N2j
    222S≠TS\ne TS̸=T ,那么要求 AAABBB 均具有一个长度为 gcd(∣A∣,∣B∣)gcd(|A|,|B|)gcd(A,B) 的周期,此周期不需要为整周期,也不需要是最小周期,并且要求填入 AAABBB∣S∣=∣T∣|S|=|T|S=T 。可以证明,上述条件是 (A,B)(A,B)(A,B) 合法的充要条件。
    假设 SSS 中有 aaaAAAbbbBBBTTT 中有 cccAAAdddBBB ,则 ∣S∣=∣T∣⇔a∣A∣+b∣B∣=c∣A∣+d∣B∣|S|=|T|\Leftrightarrow a|A|+b|B|=c|A|+d|B|S=TaA+bB=cA+dB
    因此,该情况的贡献为 ∑i=1N∑j=1N[ai+bj=ci+dj]2gcd(i,j)\sum_{i=1}^{N}\sum_{j=1}^{N}[ai+bj=ci+dj]2^{gcd(i,j)}i=1Nj=1N[ai+bj=ci+dj]2gcd(i,j)
  • 分几类讨论一下:
    111a=c,b=da=c,b=da=c,b=d ,那么贡献为 valueg=∑i=1N∑j=1N2gcd(i,j)∑g=1N2g∑d=1⌊Ng⌋μ(d)∗⌊Ngd⌋2valueg=\sum_{i=1}^{N}\sum_{j=1}^{N}2^{gcd(i,j)}\sum_{g=1}^{N}2^g\sum_{d=1}^{\lfloor\frac{N}{g}\rfloor}\mu(d)*\lfloor\frac{N}{gd}\rfloor^2valueg=i=1Nj=1N2gcd(i,j)g=1N2gd=1gNμ(d)gdN2
    222(a−c)∗(b−d)≥0(a-c)*(b-d)≥0(ac)(bd)0 ,那么 ai+bj=ci+djai+bj=ci+djai+bj=ci+dj 无正整数解,贡献为 000
    333 、否则我们可以得到一个形如 ∣A∣=xy∣B∣ (gcd(x,y)=1,x>y)|A|=\frac{x}{y}|B|\ (gcd(x,y)=1,x>y)A=yxB (gcd(x,y)=1,x>y) 的关系,贡献为 limx=∑i=1⌊Nx⌋2ilim_x=\sum_{i=1}^{\lfloor\frac{N}{x}\rfloor}2^ilimx=i=1xN2i
  • 因此,适当地预处理后,我们可以 O(1)O(1)O(1) 处理无问号的情况。
  • 考虑枚举 S,TS,TS,T 中各有多少问号变为了 AAA ,用组合数计算系数,可以得到一个 O(∣S∣∗∣T∣)O(|S|*|T|)O(ST) 的解法。
  • 注意到计算贡献时,我们只关心 a−c,b−da-c,b-dac,bd ,因此我们也可以只枚举 SSS 中变为 AAA 的问号比 TTT 中变为 AAA 的问号多几个。记 SSS 中问号个数为 sssTTT 中问号个数为 ttt ,则 SSS 中变为 AAA 的问号比 TTT 中变为 AAA 的问号多 iii 个的方案数为 (s+ti+t)\binom{s+t}{i+t}(i+ts+t)
  • 注意考虑文章开头提到的 S=TS=TS=T 的情况。
  • 时间复杂度 O(NLogN+∣S∣+∣T∣)O(NLogN+|S|+|T|)O(NLogN+S+T)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 6e5 + 5;
const int P = 1e9 + 7;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int fac[MAXN], inv[MAXN], bit[MAXN];
int n, sa, sb, sq, ta, tb, tq, ans;
int arbitrary, valueg, lim[MAXN], miu[MAXN];
char s[MAXN], t[MAXN];
int power(int x, int y) {
	if (y == 0) return 1;
	int tmp = power(x, y / 2);
	if (y % 2 == 0) return 1ll * tmp * tmp % P;
	else return 1ll * tmp * tmp % P * x % P;
}
void update(int &x, int y) {
	x += y;
	if (x >= P) x -= P;
}
int getc(int x, int y) {
	if (y > x) return 0;
	else return 1ll * fac[x] * inv[y] % P * inv[x - y] % P;
}
void gets(char *s, int &a, int &b, int &q) {
	scanf("%s", s + 1);
	int len = strlen(s + 1);
	for (int i = 1; i <= len; i++)
		if (s[i] == 'A') a++;
		else if (s[i] == 'B') b++;
		else q++;
}
void init(int n) {
	fac[0] = bit[0] = 1;
	for (int i = 1; i <= n; i++) {
		fac[i] = 1ll * fac[i - 1] * i % P;
		bit[i] = 2ll * bit[i - 1] % P;
	}
	inv[n] = power(fac[n], P - 2);
	for (int i = n - 1; i >= 0; i--)
		inv[i] = inv[i + 1] * (i + 1ll) % P;
}
void solve(int x, int y, int coef) {
	if (x == 0 && y == 0) update(ans, 1ll * coef * valueg % P);
	if (1ll * x * y >= 0) return;
	x = abs(x), y = abs(y); int g = __gcd(x, y);
	x /= g, y /= g; if (x > y) swap(x, y);
	update(ans, 1ll * lim[y] * coef % P);
}
void equal(int len) {
	int coef = 1;
	for (int i = 1; i <= len; i++) {
		if (s[i] != '?' && t[i] != '?' && s[i] != t[i]) return;
		if (s[i] == '?' && t[i] == '?') coef = 2ll * coef % P;
	}
	update(ans, 1ll * coef * arbitrary % P);
	update(ans, P - 1ll * coef * valueg % P);
}
int getmiu(int x) {
	int i = 2, ans = 1;
	while (i * i <= x) {
		if (x % i == 0) {
			x /= i;
			if (x % i == 0) return 0;
			ans = P - ans;
		}
		i++;
	}
	if (x != 1) ans = P - ans;
	return ans;
}
void calcconsts() {
	for (int i = 1; i <= n; i++)
	for (int j = 1; i * j <= n; j++)
		update(lim[i], bit[j]);
	int sum = 0;
	for (int i = 1; i <= n; i++)
		update(sum, bit[i]);
	for (int i = 1; i <= n; i++)
		update(arbitrary, 1ll * sum * bit[i] % P);
	for (int i = 1; i <= n; i++)
		miu[i] = getmiu(i);
	for (int i = 1; i <= n; i++)
	for (int j = 1; i * j <= n; j++)
		update(valueg, 1ll * bit[i] * miu[j] % P * (n / i / j) % P * (n / i / j) % P);
}
int main() {
	freopen("string.in", "r", stdin);
	freopen("string.out", "w", stdout);
	init(6e5);
	gets(s, sa, sb, sq);
	gets(t, ta, tb, tq);
	read(n), calcconsts();
	for (int i = -tq; i <= sq; i++)
		solve(sa - ta + i, sb + sq - i - tb - tq, getc(tq + sq, i + tq));
	if (sa + sb + sq == ta + tb + tq) equal(sa + sb + sq);
	writeln(ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值