题解 CF1780GDelicious Dessert

Posted rui_er 的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解 CF1780GDelicious Dessert相关的知识,希望对你有一定的参考价值。

CF1780G 后缀自动机。

SAM 板子题。

P3804 【模板】后缀自动机 (SAM) 中,我们已经会求每个等价类(SAM 状态)在原串中的出现次数。

本题中,我们需要求所有长度能被出现次数整除的子串。我们知道一个等价类中的所有字符串的长度构成一段整数区间 \\([\\operatornameminlen(v),\\operatornamemaxlen(v)]\\),其中 \\(\\operatornameminlen(v)=\\operatornamemaxlen(\\operatornamelink(v))\\)。于是想到将每个整数的因数打表到 vector 中,然后二分即可统计这一等价类中有多少子串符合条件。

复杂度 \\(\\mathcal O(n\\log n)\\)

// Problem: CF1780G Delicious Dessert
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF1780G
// Memory Limit: 500 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

//By: Luogu@rui_er(122461)
#include <bits/stdc++.h>
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
#define debug printf("Running %s on line %d...\\n",__FUNCTION__,__LINE__)
#define fileIO(s) dofreopen(s".in","r",stdin);freopen(s".out","w",stdout);while(false)
using namespace std;
typedef long long ll;
const int N = 1e6+5;

char s[N];
int n, dp[N<<1]; ll ans;
vector<int> divisors[N], e[N<<1];
template<typename T> void chkmin(T& x, T y) if(x > y) x = y;
template<typename T> void chkmax(T& x, T y) if(x < y) x = y;
struct State 
	int len, link, nxt[26];
;
struct SAM 
	State st[N<<1];
	int sz, lst;
	void init() 
		st[0].len = 0;
		st[0].link = -1;
		sz = lst = 0;
	
	void extend(char ch) 
		int u = ++sz, c = ch - \'a\';
		st[u].len = st[lst].len + 1;
		int p = lst;
		for(;p!=-1&&!st[p].nxt[c];p=st[p].link) st[p].nxt[c] = u;
		if(p == -1) st[u].link = 0;
		else 
			int q = st[p].nxt[c];
			if(st[p].len + 1 == st[q].len) st[u].link = q;
			else 
				int v = ++sz;
				st[v].len = st[p].len + 1;
				st[v].link = st[q].link;
				memcpy(st[v].nxt, st[q].nxt, sizeof(st[q].nxt));
				for(;p!=-1&&st[p].nxt[c]==q;p=st[p].link) st[p].nxt[c] = v;
				st[q].link = st[u].link = v;
			
		
		lst = u;
		dp[u] = 1;
	
sam;
int calc(int c, int x) 
	return upper_bound(divisors[c].begin(), divisors[c].end(), x) - divisors[c].begin();

void dfs(int u) 
	for(auto v : e[u]) 
		dfs(v);
		dp[u] += dp[v];
	
	if(!u) return;
	int cnt = calc(dp[u], sam.st[u].len) - calc(dp[u], sam.st[sam.st[u].link].len);
	ans += 1LL * cnt * dp[u];


int main() 
	scanf("%d%s", &n, s+1);
	rep(i, 1, n) for(int j = i; j <= n; j += i) divisors[j].push_back(i);
	sam.init();
	rep(i, 1, n) sam.extend(s[i]);
	rep(i, 1, sam.sz) e[sam.st[i].link].push_back(i);
	dfs(0);
	printf("%lld\\n", ans);
	return 0;

以上是关于题解 CF1780GDelicious Dessert的主要内容,如果未能解决你的问题,请参考以下文章

CF 1780-D. Bit Guessing Game_Codeforces Round #846 (Div. 2) D

CF1512D Corrupted Array 题解

题解CF519E

题解-比赛CF1332

CF398B题解

CF1354&CF1355 简要题解