首页 > 其他分享 >洛谷 P10716 【MX-X1-T4】「KDOI-05」简单的字符串问题

洛谷 P10716 【MX-X1-T4】「KDOI-05」简单的字符串问题

时间:2024-07-17 19:40:54浏览次数:7  
标签:P10716 typedef 洛谷 05 int long ge maxn define

洛谷传送门

一个 \(A\) 合法的充要条件为:

  • \(A\) 为 \(S_{1 \sim i}\) 的一个 border;
  • \(A\) 在 \(S_{1 \sim i}\) 中不重叠地出现 \(\ge k\) 次。

建出失配树后,发现合法的 \(A\) 在树上组成一条某个点 \(u\) 到根的链,且 \(u\) 为 \(i\) 的祖先。因此我们若知道 \(u\),答案就是 \(dep_u\)。

考虑倍增求出 \(u\)。相当于要 check 这样一个问题:

  • \(S_{1 \sim u}\) 的第 \(k\) 次不重叠出现位置是否 \(\le i\)。

考虑预处理出每个前缀 \(S_{1 \sim u}\) 对应的串在整个串中的不重叠出现位置。相当于每次找到一个位置后面第一个后缀,使得它与整个串的 LCP 长度 \(\ge u\),然后跳到它。跳的步数最多是 \(\sum\limits_{i = 1}^n \frac{n}{i} = O(n \log n)\) 所以可以暴力跳。

一个后缀与整个串的 LCP 长度可以想到 Z 函数。用并查集维护链表的 trick,从小到大枚举 \(u\),处理完 \(u\) 后把 \(z_p = u\) 的所有位置 \(p\) 删了,使得处理到 \(u\) 时,并查集中 \(z_p \ge u\) 的位置为代表元。这样即可 \(O(\alpha(n))\) 求出一个位置后面第一个 \(p\) 使得 \(z_p \ge u\) 的 \(p\)。

注意特判 \(k = 1\)。

总时间复杂度 \(O(q \log n + n \alpha(n) \log n)\)。

code
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 200100;
const int logn = 20;

int n, m, fail[maxn], dep[maxn], z[maxn], st[logn][maxn], f[logn][maxn], fa[maxn];
char s[maxn];
vector<int> vc[maxn], cv[maxn];

int find(int x) {
	return fa[x] == x ? x : fa[x] = find(fa[x]);
}

void solve() {
	scanf("%d%s%d", &n, s + 1, &m);
	for (int i = 2, j = 0; i <= n; ++i) {
		while (j && s[i] != s[j + 1]) {
			j = fail[j];
		}
		j += (s[i] == s[j + 1]);
		fail[i] = j;
	}
	for (int i = 1; i <= n; ++i) {
		f[0][i] = fail[i];
		dep[i] = dep[fail[i]] + 1;
	}
	for (int j = 1; j <= 19; ++j) {
		for (int i = 1; i <= n; ++i) {
			f[j][i] = f[j - 1][f[j - 1][i]];
		}
	}
	z[1] = n;
	for (int i = 2, l = 0, r = 0; i <= n; ++i) {
		if (i <= r) {
			z[i] = min(z[i - l + 1], r - i + 1);
		}
		while (i + z[i] <= n && s[z[i] + 1] == s[i + z[i]]) {
			++z[i];
		}
		if (i + z[i] - 1 > r) {
			l = i;
			r = i + z[i] - 1;
		}
	}
	for (int i = 1; i <= n; ++i) {
		cv[z[i]].pb(i);
		fa[i] = (z[i] ? i : i + 1);
	}
	fa[n + 1] = n + 1;
	for (int i = 1; i <= n; ++i) {
		vc[i].pb(i);
		int p = i;
		while (p + i <= n) {
			int q = find(p + 1);
			if (q == n + 1) {
				break;
			}
			p = q + i - 1;
			vc[i].pb(p);
		}
		for (int j : cv[i]) {
			fa[j] = j + 1;
		}
	}
	while (m--) {
		int x, y;
		scanf("%d%d", &x, &y);
		if (y == 1) {
			puts("1");
			continue;
		}
		int t = x;
		for (int i = 19; ~i; --i) {
			if (f[i][x] && ((int)vc[f[i][x]].size() < y || vc[f[i][x]][y - 1] > t)) {
				x = f[i][x];
			}
		}
		x = f[0][x];
		printf("%d\n", dep[x]);
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:P10716,typedef,洛谷,05,int,long,ge,maxn,define
From: https://www.cnblogs.com/zltzlt-blog/p/18308159

相关文章

  • 洛谷P1596 [USACO10OCT] Lake Counting S 题解
    看别的神犇用的都是并查集,我还是用暴搜吧(doge下面纯暴搜#include<bits/stdc++.h>usingnamespacestd;intn,m,ans;//N行M列和答案charc[105][105];//存储农田的二维向量voiddfs(intx,inty){//暴搜 if(c[x][y+1]=='W'){ c[x][y+1]='.';//将水坑改为......
  • python 解题 洛谷B2021到B2025
    B2021输出保留3位小数的浮点数n=float(input())n=n-0.000000000000001print('%.3f'%n)B2022输出保留12位小数的浮点数m=float(input())print('%.12f'%m)B2023空格分隔输出a=input()b=int(input())c=float(input())d=float(input())print(a,"",b,"......
  • iOS开发基础105-Xcode收集Crashs的各种方法
    Xcode提供了一整套工具和功能来帮助开发者收集、分析和处理应用崩溃报告。通过这些工具,开发者可以追踪和解析崩溃日志,以更加准确和及时地修复问题。以下是详细介绍Xcode工具收集崩溃报告的各种方法。一、通过设备获取崩溃报告1.连接设备将iOS设备通过USB连接到您的Mac......
  • C++题解(7) 信息学奥赛一本通:1055:判断闰年
    【题目描述】判断某年是否是闰年。如果公元a年是闰年输出Y,否则输出N。【输入】输入只有一行,包含一个整数a(0<a<3000)。【输出】一行,如果公元a年是闰年输出Y,否则输出N。【输入样例】2006【输出样例】N【知识链接:如何判断闰年】(1)能被4整除,但不......
  • 数组005 二维数组
    1#include<iostream>2usingnamespacestd;34//二维数组作为函数的参数5//注意此时的长度,是有多少行,也就是最外层有多少个6voiderweishuzu(int(*p)[4],intlen)7{8for(inti=0;i<len;i++)9for(intii=0;ii<4;ii++)10......
  • DDD | 05-什么是仓储层
    四、什么是仓储层?在DDD中,仓储(Repository)是一种设计模式,它充当了领域层与数据存储层之间的桥梁。仓储的主要职责是提供一种抽象机制,使得领域对象(尤其是聚合根)可以被透明地持久化和检索,而无需暴露底层的数据访问技术细节给领域层。这样设计的目的是为了保持领域模型的纯净性,让业务......
  • 洛谷 - P6190
    题目大意给定n点m边带权有向图,从1到\(n\)的路径中,经过一条边时可让其权值变为相反数,再变为原权值,求路径最小权值。分析先用\(Floyd\)求出全源最短路。借用\(Floyd\)数组列出\(dp\)状态,\(f_{i,j}\)表示从\(i\)到\(j\)的最短路权值。但似乎进行不下去了,我们不......
  • 题解:SP10502 VIDEO - Video game combos
    大意构造一个长度为\(k\)(\(k\)是给定的)的串\(x\),使得对于\(∀1\leqi\leqn,s_i\)在\(x\)中的出现次数之和最大。输出这个最大值。思考考虑对\(s_i\)建AC自动机,然后dp。记\(dp[i][u]\)表示为长度为\(i\)的字符串,且当前已计算的节点是Trie上的编号为\(u......
  • 005_python3 元组 字典 集合 条件控制 循环语句 编程第一步
    Python3元组1.元组的元素不能修改,使用小括号,逗号隔开,也可不用小括号,不同类型元素tup1=()  #创建空元组tup2=('he',)   #元组中只包含一个元素时,需要在元素后面添加逗号 , ,否则括号会被当作运算符使用tup3=('abc','xyz',2,4,9)2.元组使用访问元组:tup3......
  • Java基础05:类型转换
    由于Java是强类型语言,所以要进行有些运算的时候的,需要用到类型转换。整型、实型(常量)、字符型数据可以混合运算。运算中,不同类型的数据先转化为同一类型,然后进行运算。转换从低级到高级(根据容量来看)。低------------------------------------------>高byte,short,char—>i......