题解: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
*/
posted @ 2025-10-17 11:11  LUlululu1616  阅读(10)  评论(0)    收藏  举报