首页 > 其他分享 >CF1073G Yet Another LCP Problem

CF1073G Yet Another LCP Problem

时间:2023-10-27 18:24:13浏览次数:38  
标签:le LCP int sum mid Another l1 Problem operatorname

一道 *2600 调了一年,代码细节是有点粪了,但自己菜也是挺菜的。/oh/oh

考虑容斥,令 \(f(A)=\sum\limits_{i,j\in A}\operatorname{lcp}(i,j)\),那么答案就是 \(f(A\cup B)-f(A)-f(B)\)(这里的并表示可重集合并)。

令 \(A=\{a_1,a_2,\cdots ,a_m\}\),并且 \(a_1\le a_2\le\cdots\le a_m\),那么 \(f(A)=\sum\limits_{1\le i\le j\le m}\operatorname{lcp}(i,j)\)。

由于我们先前进行了容斥,所以可以忽略 \(i=j\) 的贡献,只需要考虑 \(\sum\limits_{1\le i<j\le m}\operatorname{lcp}(i,j)\) 即可。但是注意到 \(a_i\) 仍然有可能等于 \(a_j\)。

建出后缀数组。为了方便,令 \(a_i\gets \operatorname{rk}_{a_i}\),那么对于 \(a_i< a_j\),\(\operatorname{lcp}(\operatorname{sa}_i,\operatorname{sa}_j)=\min\limits_{k\in [{a_i}+1,a_j]}\operatorname{height}_k\),变成了一个子区间最小值之和的问题,可以分治解决;对于 \(a_i=a_j\),单独计算每种 \(a_i\) 的贡献,只需要求出 \(a_j=k\) 的 \(j\) 的个数 \(c_{k}\),那么 \(k\) 的贡献即为 \(\dbinom{c_k}{2}(n-\operatorname{sa}_{k}+1)\)。

然后就做完了,复杂度 \(O(n\log n)\),注意分治时不能统计到 \(a_i=a_j\) 的贡献。

// Problem: G. Yet Another LCP Problem
// Contest: Codeforces - Educational Codeforces Round 53 (Rated for Div. 2)
// URL: https://codeforces.com/problemset/problem/1073/G
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
#define pb emplace_back
#define mt make_tuple
#define mp make_pair
#define fi first
#define se second

using namespace std;
typedef long long ll;
typedef pair<int, int> pi;
typedef tuple<int, int, int> tu;
bool Mbe;

const int N = 4e5 + 400;
const int M = 20;

ll sum[N];
int n, m, q, len, a[N], b[N], pr[N], sf[N], f[N][M];
int id[N], ct[N], rk[N], sa[N], ht[N];
char s[N];

void rst() {
	memset(ct, 0, sizeof(int) * (m + 5));
	for (int i = 1; i <= n; i++) ct[rk[i]]++;
	for (int i = 1; i <= m; i++) ct[i] += ct[i - 1];
	for (int i = n; i; i--) sa[ct[rk[id[i]]]--] = id[i];
}

void SA() {
	m = 30;
	for (int i = 1; i <= n; i++) rk[i] = s[i] - 'a' + 1, id[i] = i;
	rst();
	for (int w = 1, p = 0; w <= n && p != n; w <<= 1, m = p) {
		p = 0;
		for (int i = n - w + 1; i <= n; i++) id[++p] = i;
		for (int i = 1; i <= n; i++) if (sa[i] > w) id[++p] = sa[i] - w;
		rst(), swap(rk, id), p = rk[sa[1]] = 1;
		for (int i = 2; i <= n; i++) rk[sa[i]] = (id[sa[i]] == id[sa[i - 1]] && id[sa[i] + w] == id[sa[i - 1] + w]) ? p : ++p;
	}
	for (int i = 1, j = 0; i <= n; i++) {
		if (j) j--;
		while (s[i + j] == s[sa[rk[i] - 1] + j]) j++;
		ht[rk[i]] = j;
	}
}

int qry(int l, int r) {
	if (l > r) return 0; 
	int len = __lg(r - l + 1);
	return min(f[l][len], f[r - (1 << len) + 1][len]);
}

ll conq(int l, int r) {
	if (l == r) return 0;
	int mid = (l + r) >> 1;
	ll res = conq(l, mid) + conq(mid + 1, r); sum[mid] = 0;
	for (int i = mid; i >= l; i--) sf[i] = qry(a[i] + 1, a[mid + 1]);
	for (int i = mid + 1; i <= r; i++) pr[i] = qry(a[mid] + 1, a[i]), sum[i] = sum[i - 1] + pr[i];
	int p = mid + 1, q = mid;
	while (p <= r && a[p] == a[mid]) p++;
	while (q >= l && a[q] == a[mid + 1]) q--;
	if (a[mid] == a[mid + 1]) res += 1ll * (sum[r] - sum[p - 1]) * (mid - q);
	for (int i = mid + 1; i <= r; i++) pr[i] = qry(a[q] + 1, a[i]), sum[i] = sum[i - 1] + pr[i];
	for (int i = q, j = mid + 1; i >= l; i--) {
		while (j <= r && sf[i] <= pr[j]) j++;
		res += 1ll * (j - mid - 1) * sf[i] + sum[r] - sum[j - 1];
	}
	return res;
}

ll calc(int l, int r) {
	for (int i = l; i <= r; i++) a[i] = b[i];
	sort(a + l, a + r + 1);
	ll res = 0;
	for (int i = l; i <= r; i++) {
		int j = i;
		while (j < r && a[j + 1] == a[i]) j++;
		res += 1ll * (j - i + 1) * (j - i) / 2 * (n - a[i] + 1), i = j;
	}
	for (int i = l; i <= r; i++) a[i] = rk[a[i]];
	sort(a + l, a + r + 1);
	return res + conq(l, r);
}

void solve() {
	cin >> n >> q >> (s + 1), SA();
	for (int i = 1; i <= n; i++) f[i][0] = ht[i];
	for (int j = 1; (1 << j) <= n; j++)
		for (int i = 1; i + (1 << j) - 1 <= n; i++)
			f[i][j] = min(f[i][j - 1], f[i + (1 << j - 1)][j - 1]);
	while (q--) {
		int l1, l2; cin >> l1 >> l2;
		for (int i = 1; i <= l1; i++) cin >> b[i];
		for (int i = 1; i <= l2; i++) cin >> b[l1 + i];
		ll s1 = calc(1, l1 + l2), s2 = calc(1, l1), s3 = calc(l1 + 1, l1 + l2);
		// cout << s1 << ' ' << s2 << ' ' << s3 << '\n';
		cout << s1 - s2 - s3 << '\n';
	}
}

bool Med;
int main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	cerr << (&Mbe - &Med) / 1048576.0 << " MB\n";
	#ifdef FILE
		freopen("1.in", "r", stdin);
		freopen("1.out", "w", stdout);
	#endif
	int T = 1;
	// cin >> T;
	while (T--) solve();
	cerr << (int)(1e3 * clock() / CLOCKS_PER_SEC) << " ms\n";
	return 0;
}

标签:le,LCP,int,sum,mid,Another,l1,Problem,operatorname
From: https://www.cnblogs.com/Ender32k/p/17792935.html

相关文章

  • SSL certificate problem: unable to get local issuer certificate 错误解决
    终端报了如下错误gitSSLcertificateproblem:unabletogetlocalissuercertificate这个问题是由于没有配置信任的服务器HTTPS验证。默认,cURL被设为不信任任何CAs,就是说,它不信任任何服务器验证。在网上查了很多方法,最终使用如下方法解决的只需要执行下面命令就可以解决:git......
  • [HDU 3483] A Very Simple Problem 题解
    题目描述快速求出下面式子的值:\[\left(\sum\limits_{k=1}^{N}k^{x}x^{k}\right)\bmodM\]其中\(1≤N,M≤2\times10^9\),并且\(1≤x≤50\)。题解(solution)对于该类题目,\(N\)很大,而\(x\)很小,考虑矩阵快速幂优化。对于每一个\(N\)的答案,我们用\(f(N)\)来......
  • 题解 CF903G【Yet Another Maxflow Problem】
    加边\(A_n\stackrel{0}{\to}A_{n+1}\),\(B_0\stackrel{0}{\to}B_1\)。称形如\(A_i\toA_{i+1}\)的边为左部边,形如\(B_j\toB_{j+1}\)的边为右部边,形如\(A_i\toB_j\)的边为中间边。根据最大流最小割定理,将最大流问题转化为最小割问题求解。显然,至少存在一组最小割,包含恰好......
  • 【LeetCode】LCP 06.拿硬币
    描述桌上有n堆力扣币,每堆的数量保存在数组coins中。我们每次可以选择任意一堆,拿走其中的一枚或者两枚,求拿完所有力扣币的最少次数。示例输入:[4,2,1]输出:4解释:第一堆力扣币最少需要拿2次,第二堆最少需要拿1次,第三堆最少需要拿1次,总共4次即可拿完。限制1<=n<=41<=co......
  • #结论#CF1776G Another Wine Tasting Event
    题目给定一个长度为\(2n-1\)的字符串,问一组使得\(n\)个长度不小于\(n\)的区间中字母W的个数相等的字母W的个数分析首先结论就是\(\max_{i=1}^n\{cW[i\dotsi+n-1]\}\)一定是合法解以这组解为基准,左右端点如果向外扩展那么个数一定会更多或者不变,而此时由于当前字母......
  • BUG:cURL error 60: SSL certificate problem: unable to get local issuer certificat
    PHPssl证书问题(我的环境是phpstudy)解决方案:1.https://curl.se/docs/caextract.html 打开网址,下载最新PEM 2.将证书放进对应PHP版本extras/ssl文件里面3.修改对应版本的PHP.INI 4.重启PHP问题解决 ......
  • Vivado生成bitstream时报错[Opt 31-67] Problem: A LUT3 cell in the design is missi
    这个原因主要是因为有一个引脚没有用到,解决方法。1、打开Schematic。2、根据提示的模块去找,比如说我的报错。[Opt31-67]Problem:ALUT3cellinthedesignismissingaconnectiononinputpinI1,whichisusedbytheLUTequation.Thispinhaseitherbeenleftun......
  • [920] Copy the font style from one cell in a table of a Word document to another
    TocopythefontstylefromonecellinatableofaWorddocumenttoanothercellusingPythonandthepython-docxlibrary,youcanaccessthefontpropertiesofthesourcecellandapplythemtothetargetcell.Here'showyoucandoit:First,ma......
  • Paper Reading: Sample and feature selecting based ensemble learning for imbalanc
    目录研究动机文章贡献本文方法基于聚类的分层随机欠采样特征选择样本和特征选择的集成学习基于随机森林的SFSHEL实验结果数据集和实验设置KEEL数据集的比较HeartFailure数据集的比较优点和创新点PaperReading是从个人角度进行的一些总结分享,受到个人关注点的侧重和实力所限......
  • Codeforces Round 893 (Div. 2) C. Yet Another Permutation Problem
    有一个\(gcd\)游戏,按以下步骤进行:选择一个\(n\)的排列\(p_1,p_2,\cdots,p_n\)。对于每个\(i\),\(d_i=gcd(p_i,p_{i\%n+1})\)排列\(p\)的\(score\)为数组\([d_1,d_2,\cdots,d_n]\)中不同数的个数。给一个\(n\),需要构造一个排列\(p\),使得\(sco......