专栏文章
CF794G 题解
CF794G题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mipswphg
- 此快照首次捕获于
- 2025/12/03 17:25 3 个月前
- 此快照最后确认于
- 2025/12/03 17:25 3 个月前
这题其实不难。
Update 2025.3.26:修改题解 Markdown。
Update 2025.3.27:修改题解中错误的式子,并重写逻辑清晰的代码。
Part 1.
首先,考虑没有
? 如何做。分两种情况:
- 字符串 与 长度相等。
- 字符串 与 长度不相等。
先考虑 和 长度不相等怎么做。
首先,将两个串中共同的字符删除。
比如
ABBAAA 和 BABBB,两个串有一个共同的 A,两个共同的 B,删除之后变为 AAA 和 BB。那么显然,01 串 与 的长度比为
设 为 , 为 , 为长度相等的 01 串。
替换一下 和 。
ABBAAA 变为 。BABBB 变为 。如果要让替换后的 01 串相等,那么我们需要保证 。
如果我们多观察一下别的 和 ,使用相同的步骤操作,我们会发现,若 和 长度最简比为 ,那么那么 ,。
其中 是一个 01 串。 表示 个 拼接在一起。
由于 和 的长度限制是 ,那么 的长度限制就是 。
我们求出长度小于等于 的非空 01 串即为这种情况的答案。
答案 。
注意如果 或者 在删除共同字符之后为空,那么无解。
接下来考虑 和 长度相等怎么做。
这种情况还要再细分。
-
和 完全相等。显然, 和 可以任意取。答案为 。
-
和 中
A的数量相等(并且B的数量相等)。这种情况 和 的长度仍然是可以任取,但是由于 和 不相同,那么必然会有某些位置A,B(或相反),那么 和 中必然会有一个串是另一个串的前缀。 然后,举个例子, 长度为 , 长度为 。设 。标红是因为无论后面接上的是 还是 ,前四个都一定是 。那么可以得出 。那么 并且 。所以 。简单证明或者感性理解即可得知: 和 的最长重复单元长度为:。那么答案即为 (推式子见结尾)。前缀和处理 即可。 -
以上两种情况都不符合。显然,对于这种情况, 一定等于 。那么答案为 。
以上解决了无
? 的情况。Part 2.
现在解决有
? 的情况。分两种情况:
- 字符串 与 长度相等。
- 字符串 与 长度不相等。
还是先考虑 和 长度不相等怎么做。
首先,我们计算出 与 中含有的
A 和 B 的差。设 表示 中
A 的个数,其他同理。那么:记
A 个数差 ,B 个数差 。然后,我们考虑最边界的情况, 中的所有
? 设为 A; 中的所有 ? 设为 B。那么:
接下来,我们考虑修改问号的值会发生什么。
举个例子:
为方便染色,使用 。
变为边界情况:
接下来我们以这个状态为基准,我们发现,翻转任意一个标红字母(将
A 变为 B,或相反),对 和 的影响都是一样的。将 中的A变为B,会导致 加一,而A的数量减一, 减一。若将 中的B变为A,同样会导致 加一, 减一。
那么我们可以枚举有多少个字母从基准状态翻转了。
标红字母个数为 ,翻转字母数量为 ,那么总共可能的情况有 种,,。
然后我们考虑每组 和 怎么计算贡献。
如果 ,那么则代表两者同号或有一项等于 ,那么就对应了这种情况:
注意如果 或者 在删除共同字符之后为空,那么无解。
只有两者异号,才能产生贡献。
然后两者异号,就可以直接用上面的无
?、 不等长解决。 长度最简比即为 与 的最简比。
设 表示 , 时的答案。
最终答案为:
直接求解,, 来自快速幂和 。
总复杂度 。
接下来考虑 长度相等的情况。
我们需要先扫描一遍,判断是否有某种组合,让 ,如果有,计算出情况数 (same)。
再计算出边界情况下的 和 。
接下来,我们如果需要让两个串
A 的数量相等,那么应当使 。对应的情况数 (equal),要注意这种情况是严格包含 的情况的,所以要减掉。
若 或 ,则 ,因为不可能使两串
A 数量相等。剩下的情况则为普通情况,数量 (normal)。
接下来我们一个个计算贡献。
same:相同则任意取:。
equal:长度任意:。
normal:,。
最终答案为:
前缀和处理欧拉函数,复杂度 。
接下来讲一下一些式子。
在上面经常会看到 出现。
这个即为长度小于等于 的 01 串的数量。
因为 ,小学数学即可证明。
考虑这块的含义:。
这块即为数对 ,满足 ,且 互质的个数。
首先,我们知道欧拉函数 表示 到 中与 互质的数的个数。
那么我们先假定 ,那么显然数对个数为 。
那么相反的情况:,与上面相同。
然后就是 ,只有 符合,贡献为 。
那么原式等于:
要注意取模、爆 long long。
这些都是因为取模和爆 long long WA 的。

代码
CPP#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int N = 1000005, P = 1000000007;
string x, y;
int n;
int Gcd(int a, int b) {
if(b == 0) return a;
return Gcd(b, a % b);
}
int ksm(int a, int n) {
if(n == 0) return 1;
if(n == 1) return a % P;
int d = ksm(a, n / 2);
d = d * d % P;
if(n & 1) d = d * a % P;
return d;
}
int calc(int da, int db) {
if(da * db >= 0) return 0;
da = abs(da);
db = abs(db);
int gd = Gcd(da, db);
int a = da / gd;
int b = db / gd;
int len = n / max(a, b);
return (ksm(2, len + 1) - 2 + P) % P;
}
int frac[N], ifrac[N];
int phi[N];
int sumphi[N];
bool not_prime[N];
int plist[N], h;
int C(int n, int m) {
return frac[n] * ifrac[n - m] % P * ifrac[m] % P;
}
void init() {
frac[0] = 1;
for(int i = 1; i < N; i ++) {
frac[i] = frac[i - 1] * i % P;
}
ifrac[N - 1] = ksm(frac[N - 1], P - 2);
for(int i = N - 2; i >= 0; i --) {
ifrac[i] = ifrac[i + 1] * (i + 1) % P;
}
not_prime[1] = 1;
phi[1] = 1;
for(int i = 2; i < N; i ++) {
if(!not_prime[i]) {
phi[i] = i - 1;
plist[++ h] = i;
}
for(int j = 1; j <= h && plist[j] * i < N; j ++) {
not_prime[plist[j] * i] = 1;
if(i % plist[j] == 0) {
phi[plist[j] * i] = phi[i] * plist[j];
break;
}
phi[plist[j] * i] = phi[plist[j]] * phi[i];
}
}
for(int i = 1; i < N; i ++) {
sumphi[i] = (sumphi[i - 1] + phi[i]) % P;
}
return ;
}
void diff() {
int da = 0, db = 0;
int cnt = 0;
for(int i = 0; x[i]; i ++) {
if(x[i] == 'A') da ++;
if(x[i] == 'B') db ++;
if(x[i] == '?') {cnt ++; da ++; }
}
for(int i = 0; y[i]; i ++) {
if(y[i] == 'A') da --;
if(y[i] == 'B') db --;
if(y[i] == '?') {cnt ++; db --; }
}
int ans = 0;
for(int k = 0; k <= cnt; k ++) {
ans += C(cnt, k) * calc(da - k, db + k) % P;
ans %= P;
}
printf("%d\n", ans);
return ;
}
void same() {
int cnts = 1, cnte = 0, cntn = 0;
int da = 0, db = 0;
int cnt = 0;
for(int i = 0; x[i]; i ++) {
if(x[i] == 'A') da ++;
if(x[i] == 'B') db ++;
if(x[i] == '?') {da ++; cnt ++; }
if(y[i] == 'A') da --;
if(y[i] == 'B') db --;
if(y[i] == '?') {db --; cnt ++; }
if(x[i] != y[i] && x[i] != '?' && y[i] != '?') {
cnts = 0;
} else if(x[i] == y[i] && x[i] == '?') {
cnts *= 2;
cnts %= P;
}
}
cnte = (da < 0 || da > cnt) ? 0 : (C(cnt, da) - cnts + P) % P;
cntn = (ksm(2, cnt) - cnts - cnte + 2 * P) % P;
int sume = 0, pw = 1;
for(int k = 1; k <= n; k ++) {
pw = pw * 2 % P;
sume += pw * ((2 * sumphi[n / k] % P - 1 + P) % P) % P;
sume %= P;
}
int ans = {
cnts * ksm((ksm(2, n + 1) - 2 + P) % P, 2) % P +
cnte * sume +
cntn * (ksm(2, n + 1) - 2 + P) % P
} ;
ans %= P;
printf("%d\n", ans);
return ;
}
signed main() {
init();
cin >> x >> y >> n;
if(x.size() == y.size()) {
same();
} else {
diff();
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...