ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CodeForces 1286E Fedya the Potter Strikes Back

2022-07-02 13:06:06  阅读:177  来源: 互联网

标签:int res Fedya Potter Back pos mp border ll


洛谷传送门

CF 传送门

KMP 好题。

思路

合法的子区间其实就是原串的 \(\mathrm{border}\),考虑维护 \(\mathrm{border}\) 的集合。每次加入一个字符,就保留原来合法的 \(\mathrm{border}\) 并加入新的合法 \(\mathrm{border}\)(如果 \(s_1 = s_i\))。

重点在于如何删掉不合法的 \(\mathrm{border}\)。设 \(fa_{i,j}\) 表示 \([1,pos+1]\) 能被 \([i-pos+1,i]\) 和字符 \(j\) 拼接成的 \(pos\) 最大值,每次可以 \(O(26)\) 处理。枚举 \(i - 1\) 后接上的 \(\ne s_i\) 的字符,暴力跳 \(fa\) 删前缀即可。用一个 map 维护每个 \(w_i\) 出现的次数,则删完之后把 map 中 \(> w_i\) 的权值全部修改为 \(w_i\) 即可。

线段树维护区间 \(w_i\) 最小值,时间复杂度为 \(O(n \log n + 26n)\)。

代码

code
/*

p_b_p_b txdy
AThousandMoon txdy
AThousandSuns txdy
hxy txdy

*/

#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second

using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;

struct bignum {
	const int P = 10000;
	
	int a[10], n;
	
	void add(ll x) {
		int pos = 0;
		while (x) {
			a[pos] += x % P;
			x /= P;
			++pos;
		}
		for (int i = 0; i < 9; ++i) {
			a[i + 1] += a[i] / P;
			a[i] %= P;
		}
		n = 9;
		while (n && !a[n]) {
			--n;
		}
	}
	
	ll mod(ll p) {
		ll res = 0;
		for (int i = n; ~i; --i) {
			res = (res * P + a[i]) % p;
		}
		return res;
	}
	
	void write() {
		printf("%d", a[n]);
		for (int i = n - 1; ~i; --i) {
			printf("%04d", a[i]);
		}
		putchar('\n');
	}
} ans;

const int maxn = 600100;

int n, a[maxn], b[maxn], tree[maxn << 2], fail[maxn];
int fa[maxn][26];
map<ll, ll> mp;

void pushup(int x) {
	tree[x] = min(tree[x << 1], tree[x << 1 | 1]);
}

void update(int rt, int l, int r, int x, int y) {
	if (l == r) {
		tree[rt] = y;
		return;
	}
	int mid = (l + r) >> 1;
	if (x <= mid) {
		update(rt << 1, l, mid, x, y);
	} else {
		update(rt << 1 | 1, mid + 1, r, x, y);
	}
	pushup(rt);
}

int query(int rt, int l, int r, int ql, int qr) {
	if (ql <= l && r <= qr) {
		return tree[rt];
	}
	int mid = (l + r) >> 1, res = 2e9;
	if (ql <= mid) {
		res = min(res, query(rt << 1, l, mid, ql, qr));
	}
	if (qr > mid) {
		res = min(res, query(rt << 1 | 1, mid + 1, r, ql, qr));
	}
	return res;
}

void solve() {
	char op[9];
	scanf("%d%s%d", &n, op, &b[1]);
	a[1] = op[0] - 'a';
	update(1, 1, n, 1, b[1]);
	ans.add(b[1]);
	ans.write();
	ll cur = 0;
	for (int i = 2, j = 0; i <= n; ++i) {
		scanf("%s%d", op, &b[i]);
		a[i] = (op[0] - 'a' + ans.mod(26)) % 26;
		b[i] ^= ans.mod(1LL << 30);
		update(1, 1, n, i, b[i]);
		ans.add(query(1, 1, n, 1, i));
		if (a[1] == a[i]) {
			cur += b[i];
			++mp[b[i]];
		}
		while (j && a[i] != a[j + 1]) {
			j = fail[j];
		}
		if (a[i] == a[j + 1]) {
			++j;
		}
		fail[i] = j;
		for (int k = 0; k < 26; ++k) {
			fa[i][k] = fa[fail[i]][k];
		}
		fa[i][a[fail[i] + 1]] = fail[i];
		for (int k = 0; k < 26; ++k) {
			if (a[i] == k) {
				continue;
			}
			for (int u = fa[i - 1][k]; u; u = fa[u][k]) {
				int mn = query(1, 1, n, i - u, i - 1);
				cur -= mn;
				--mp[mn];
			}
		}
		ll cnt = 0;
		vector<ll> tv;
		for (auto it = mp.upper_bound(b[i]); it != mp.end(); ++it) {
			tv.pb(it->fst);
			cnt += it->scd;
			cur -= it->fst * it->scd;
		}
		for (ll x : tv) {
			mp.erase(x);
		}
		cur += cnt * b[i];
		mp[b[i]] += cnt;
		ans.add(cur);
		ans.write();
	}
}

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

标签:int,res,Fedya,Potter,Back,pos,mp,border,ll
来源: https://www.cnblogs.com/zltzlt-blog/p/16437093.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有