其他分享
首页 > 其他分享> > AtCoder Beginner Contest 213

AtCoder Beginner Contest 213

作者:互联网

相隔大约一周才补题,原因是太弱了。

H 正解是分治 FFT,目前不会所以留坑在这里。

ABC213

\(\mathcal A\sim E\)

赛时平均一题 5 min,而且主要是读题时间,所以放在一起提一句。

A 异或基本运算,B 排序,C 离散化,D DFS 序,E 0/1 BFS,每以一个障碍物为中心的 \(3\times 3\) 均为 \(1\) 步到达。

代码懒得放。

\(\mathcal F\)

针对一个字符串的每个后缀,求出它与所有后缀的 LCP 之和。

比较套路的 SA + 单调栈。

考虑 SA,每个点对当前位的贡献通过单调栈简单维护即可,正反各扫一遍。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long LL;
const int N = 1e6 + 10;
int n, tot, stk[N], wid[N];
int bac[N], sa[N], rk[N], SA[N], RK[N], lcp[N];
char str[N]; LL ans[N];

int read(){
	int x = 0, f = 1; char c = getchar();
	while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
	return x * f;
}

void Get_SA(){
	for(int i = 1; i <= n; i ++) bac[str[i]] ++;
	for(int i = 1; i <= 256; i ++) bac[i] += bac[i - 1];
	for(int i = 1; i <= n; i ++) sa[bac[str[i]] --] = i;
	for(int i = 1; i <= n; i ++) rk[sa[i]] = rk[sa[i - 1]] + (str[sa[i]] != str[sa[i - 1]]);

	for(int p = 1; p <= n; p <<= 1){
		for(int i = 1; i <= n; i ++) bac[rk[sa[i]]] = i;
		for(int i = n; i >= 1; i --) if(sa[i] > p) SA[bac[rk[sa[i] - p]] --] = sa[i] - p;
		for(int i = n; i > n - p; i --) SA[bac[rk[i]] --] = i;
		#define comp(x, y) (rk[x] != rk[y] || rk[x + p] != rk[y + p])
		for(int i = 1; i <= n; i ++) RK[SA[i]] = RK[SA[i - 1]] + comp(SA[i - 1], SA[i]);
		for(int i = 1; i <= n; i ++) sa[i] = SA[i], rk[i] = RK[i];
		if(rk[sa[n]] == n) break;
	}
	
	for(int i = 1; i <= n; i ++){
		int j = sa[rk[i] - 1], k = max(lcp[rk[i - 1]] - 1, 0);
		while(str[i + k] == str[j + k] && str[i + k]) k ++;
		lcp[rk[i]] = k;
	}
}

int main(){
	scanf("%d", &n);
	scanf("%s", str + 1);
	Get_SA();
	LL now;
	tot = now = 0;
	for(int i = 2; i <= n; i ++){
		int width = 1;
		while(tot && stk[tot] >= lcp[i]){
			now -= 1LL * wid[tot] * stk[tot];
			width += wid[tot];
			tot --;
		}
		stk[++ tot] = lcp[i]; wid[tot] = width;
		now += 1LL * wid[tot] * stk[tot];
		ans[sa[i]] += now;
	}
	tot = now = 0;
	for(int i = n; i >= 1; i --){
		ans[sa[i]] += now;
		int width = 1;
		while(tot && stk[tot] >= lcp[i]){
			now -= 1LL * wid[tot] * stk[tot];
			width += wid[tot];
			tot --;
		}
		stk[++ tot] = lcp[i]; wid[tot] = width;
		now += 1LL * wid[tot] * stk[tot];
	}
	for(int i = 1; i <= n; i ++) printf("%lld\n", ans[i] + n - i + 1);
	return 0;
}

\(\mathcal G\)

给定一个无向图,任意选择一些边,对于每个点 \(2\leq k\leq n\),求出使 \(1,k\) 联通的方案数。

这个大写 G 的标题怎么这么鬼畜

标签:AtCoder,wid,213,Beginner,int,tot,stk,--,now
来源: https://www.cnblogs.com/lpf-666/p/15134228.html