题解:CF718E Matvey's Birthday
发现是两个月前 8.20 模拟赛搬的还加强了,时隔两个月给他补了。
题意:给出一个串,可以在相邻的元素移动,或者在相同的字符间移动,代价都是 \(1\),问这个图的直径和取到直径的点对的个数,\(n\le 10^5\) 字符集大小为 \(8\)。可以做到 \(n\le 10^6\) 且字符集大小为 \(18\)。
做法:
为了方便,称在相邻元素移动为一操作,同种字符移动为而操作
首先考虑怎么描述两个点 \(x,y\) 的距离,首先很明显我可以一直用第一种,代价为 \(|x-y|\);第二种是我考虑在某个字符的位置传送一次,记 \(f_{i,c}\) 代表我从 \(i\) 出发,到达一个字符 \(c\) 的最小步数,那么代价是 \(\min f_{x,c}+f_{y,c}+1\)。
我们先统计满足第二种条件的,第一种比较方便。
我们注意到,如果假设 \(g_{i,j}\) 代表我从任意一个第 \(i\) 种字符的位置走到任意一个 \(j\) 种字符的位置的最小距离,\(id_i\) 代表 \(i\) 位置的字符,那么会有 \(g_{id_x,c}\le f_{x,c}\le g_{id_x,c}+1\),也很好理解,我可以通过一次操作二到满足 \(g\) 最小值的位置再走到字符 \(c\)。
显然我们可以在 \(O(nk)\) 的时间内轻松计算 \(f,g\),\(k\) 是字符集。
再考虑第 \(x\) 种字符和第 \(y\) 种字符中所有字符的路径,记 \(v = \min g_{x,c}+g_{y,c}+1\),那么对于从第 \(x\) 种字符到第 \(y\) 种字符的距离一定在 \([v,v+2]\) 间,我们只需要管到底是 \(v,v+1,v+2\) 哪一个就可以了。
先考虑为 \(v\) 的情况,假设字符为 \(x\) 的位置为 \(i\),为 \(y\) 的位置的 \(j\),要求 \(f_{i, c}=g_{x,c},f_{j,c}=g_{y,c}\),那么我们对于所有的 \(i\),预处理出来 \(T_i=\{c|f_{i,c}=g_{id_i,c}\}\),再算出来 \(S_0=\{c|g_{x,c}+g_{y,c}+1=v\}\),那么要求 \(T_i\cap T_j\cap S_0 \not= \varnothing\),看出来压位之后,就等于 \(T_i\land T_j\land S_0 \not= 0\),这个东西很可以直接对 \(T_i\),把他压到 \(F_x\) 这个集合幂级数里计数,然后 \(F_x,F_y\) 做与卷积即可。
然后考虑剩下两个,\(v+1\) 我们需要分讨两边哪个 \(+1\),有点麻烦,我们考虑 \(v+2\) 的情况再用整体情况减去得到 \(v+1\) 的方案数。那么首先要求 \(T_i\cap S_0=\varnothing\),否则我这一侧就可以取到等号,距离就会 \(\le v+1\)。同时,考虑 \(S_1=\{c|g_{x,c}+g_{y,c}+1=v+1\}\),那么 \(T_i\cap T_j\cap S_1 =\varnothing\)。所以我们直接把 \(T_i\cap S_0 = \varnothing\) 的拉出来,还是做与卷积,然后算与 \(S_1\) 无交的个数。
记得最后统计只用一操作的,注意到我上述方式的距离最大值只有 \(15\),也就是两倍字符集 \(-1\) 比较明显。所以考虑有可能只用操作一的这种点对只有 \(O(n)\) 个,直接枚举然后暴力枚举用操作二的字符,两种方式比较一下代价就可以了。
假设字符集为 \(k\),总复杂度 \(O(nk^2+2^kk^3)\)。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1e6 + 5, N = 8;
int n;
string s;
struct Poly {
vector<int> a;
int size() {
return a.size();
}
void resize(int N) {
a.resize(N);
}
void clear() {
for (int i = 0; i < size(); i++)
a[i] = 0;
}
int& operator[](int x) {
return a[x];
}
void fwt(int f) {
int n = size();
for (int h = 2; h <= n; h <<= 1)
for (int i = 0; i < n; i += h)
for (int j = i; j < i + h / 2; j++)
a[j] = (a[j] + a[j + h / 2] * f);
}
} h[19], x, y;
int g[19][19], f[maxn][19], id[maxn], ans[maxn], sid[maxn];
vector<int> vec[19];
int fx[] = {1, -1};
signed main() {
cin >> n >> s, s = ' ' + s;
for (int i = 1; i <= n; i++)
id[i] = s[i] - 'a' + 1;
for (int i = 1; i <= n; i++)
vec[id[i]].push_back(i);
memset(g, 0x3f, sizeof(g));
memset(f, 0x3f, sizeof(f));
for (int i = 1; i <= N; i++) {
if(!vec[i].size())
continue;
g[i][i] = 0;
queue<int> q;
for (int j = 0; j < vec[i].size(); j++)
q.push(vec[i][j]), f[vec[i][j]][i] = 0;
ans[1] += vec[i].size() * (vec[i].size() - 1) / 2;
while(!q.empty()) {
int u = q.front();
q.pop();
// cout << i << " " << u << " " << " " << f[u][i] << endl;
if(g[0][0] == g[id[u]][i]) {
g[id[u]][i] = f[u][i];
for (int j = 0; j < vec[id[u]].size(); j++) {
int p = vec[id[u]][j];
if(f[p][i] > g[id[u]][i] + 1) {
f[p][i] = g[id[u]][i] + 1;
q.push(p);
}
}
}
for (int t = 0; t < 2; t++) {
int v = u + fx[t];
if(v < 1 || v > n)
continue;
if(f[v][i] > f[u][i] + 1)
f[v][i] = f[u][i] + 1,
q.push(v);
}
}
}
// if(n <= 100) {
for (int i = 1; i <= N; i++)
h[i].resize((1 << N));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= N; j++)
if(f[i][j] == g[id[i]][j])
sid[i] |= (1 << j - 1);
h[id[i]][sid[i]]++;
}
// cout << g[1][2] << " " << g[2][3] << " " << g[1][3] << " " << g[2][1] << " " << g[3][2] << " " << g[3][1] << endl;
for (int i = 1; i <= N; i++)
h[i].fwt(1);
x.resize((1 << N)), y.resize(1 << N);
for (int i = 1; i <= N; i++) {
for (int j = i + 1; j <= N; j++) {
if(!vec[i].size() || !vec[j].size())
continue;
int v0 = 0, v1 = vec[i].size() * vec[j].size(), v2 = 0, v = 2e9;
int s0 = 0, s1 = 0;
for (int k = 1; k <= N; k++)
v = min(v, g[i][k] + g[j][k] + 1);
for (int k = 1; k <= N; k++)
if(g[i][k] + g[j][k] + 1 == v)
s0 |= (1 << k - 1);
for (int k = 1; k <= N; k++)
if(g[i][k] + g[j][k] + 1 == v + 1)
s1 |= (1 << k - 1);
for (int k = 0; k < (1 << N); k++)
x[k] = h[i][k] * h[j][k];
x.fwt(-1);
for (int k = 0; k < (1 << N); k++)
if(s0 & k)
v0 += x[k];
x.clear(), y.clear();
for (int k = 0; k < vec[i].size(); k++)
x[sid[vec[i][k]]] += ((sid[vec[i][k]] & s0) == 0);
for (int k = 0; k < vec[j].size(); k++)
y[sid[vec[j][k]]] += ((sid[vec[j][k]] & s0) == 0);
x.fwt(1), y.fwt(1);
for (int k = 0; k < (1 << N); k++)
x[k] = x[k] * y[k];
x.fwt(-1);
for (int k = 0; k < (1 << N); k++) {
if(!(k & s1))
v2 += x[k];
}
v1 -= v0 + v2;
ans[v] += v0, ans[v + 1] += v1, ans[v + 2] += v2;
// cout << i << " " << j << " " << v << " " << v0 << " " << v1 << " " << v2 << " " << s0 << endl;
}
}
for (int i = 1; i <= n; i++) {
for (int j = i + 1; j <= min(i + 15, n); j++) {
int dis = 2e9;
for (int k = 1; k <= N; k++)
dis = min(dis, f[i][k] + f[j][k] + 1);
if(dis > j - i)
ans[dis]--, ans[j - i]++;
}
}
for (int i = 2 * N - 1; i >= 0; i--) {
if(ans[i]) {
cout << i << " " << ans[i] << endl;
return 0;
}
}
// }
return 0;
}
/*
10
aaabbbcccc
*/

浙公网安备 33010602011771号