The Preliminary Contest for ICPC Asia Xuzhou 2019 G Colorful String(回文树 | manacher)

9 篇文章 0 订阅
1 篇文章 0 订阅

G. Colorful String

题意: 给出一个字符串,询问不同回文子串的权值之和。每个回文子串的权值为回文子串不同字母的个数。

题解: 回文树预处理出所有本质不同的回文子串及其出现次数,对于区间不同字母个数,可以对26个字母做前缀和。预处理后,计算方式就是每一个本质不同的回文子串的区间不同字母数量乘以出现次数。

实际上用 m a n a c h e r manacher manacher也可以做这道题的。首先,通过 m a n a c h e r manacher manacher我们可以先预处理出对于每个位置的最长回文半径,其次我们可以预处理出对于每个位置最近的26个字母。然后我们枚举每个位置,对于在其最长回文半径内的字母,它的贡献是所有长度在 [ 2 ⋅ ( i − r a d i u s i ) , r a d i u s i ] [2⋅(i−radiusi),radiusi] [2(iradiusi),radiusi]的回文子串数量。最后我们累加每个位置最长回文半径内的字母贡献即可。

代码

  • 回文树版本
const int N = 3E5+10;
struct PAM{
	int nxt[N][26], fail[N], len[N], cnt[N], S[N], pos[N];
	int tot,n,last;
	inline int newnode(int x) { 
		memset(nxt[tot],0,sizeof nxt[tot]); 
		cnt[tot] = 0, len[tot] = x; return tot++;
	}
	inline void init() {
		newnode(tot = 0), newnode(S[0] = -1), fail[last = n = 0] = 1;
	}
	inline int getfail(int x) {
		while(S[n - len[x] - 1] != S[n]) x = fail[x]; return x;
	}
	inline void Insert(int c) {
		c = c - 'a';
		S[++n] = c;
		int cur = getfail(last);
		if(!nxt[cur][c]) {
			int now = newnode(len[cur] + 2);
			fail[now] = nxt[getfail(fail[cur])][c];
			nxt[cur][c] = now;
		}
		last = nxt[cur][c]; cnt[last]++;
		pos[last] = n;
	}
	inline void getsum() {
		for(int i = tot - 1; i >= 0; --i) {
			cnt[fail[i]] += cnt[i];
		}
	}
}pam;

char s[N];
int sum[N][26];

int getsum(int l,int r) 
{
	int ret = 0;
	for(int i = 0; i < 26; ++i) if(sum[r][i] - sum[l - 1][i] > 0) ret++;
	return ret;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
    ios::sync_with_stdio(false); cin.tie(0);
	cin >> s + 1;
	int n = strlen(s + 1);
	for(int i = 1; i <= n; ++i) {
		for(int j = 0; j < 26; ++j) {
			sum[i][j] = sum[i - 1][j];
		}
		sum[i][s[i] - 'a']++;
	}
	pam.init();
	for(int i = 1; i <= n; ++i) {
		pam.Insert(s[i]);
	}
	pam.getsum();
	int l,r;
	long long ans = 0;
	for(int i = 2; i < pam.tot; ++i) {
		l = pam.pos[i] - pam.len[i] + 1;
		r = pam.pos[i];
		ans += 1LL * getsum(l,r) * pam.cnt[i];
	}
	cout << ans << '\n';
    return 0;
}

  • m a n a c h e r manacher manacher版本
#include<bits/stdc++.h>
using namespace std;
#ifndef ONLINE_JUDGE
#define dbg(args...)                                   \
    do{                                                \
	        cout << "\033[32;1m" << #args << " -> ";   \
         err(args);                                    \
      } while(0)                                       
#else
#define dbg(...)
#endif
void err()
{
    cout << "\033[39;0m" << endl;
}
template <template <typename...> class T, typename t, typename... Args>
void err(T<t> a, Args... args)
{
    for (auto x : a) cout << x << ' ';
    err(args...);
}
template <typename T, typename... Args>
void err(T a, Args... args)
{
    cout << a << ' ';
    err(args...);
}
/****************************************************************************************************/
typedef long long LL;
const int N = 6E5+10;
int last[N][30],p[N];
char s[N],st[N];
int change()
{
    int len=strlen(st);
    int j=2;
    s[0]='^';
    s[1]='$';
    for (int i=0;i<len;i++)
    {
        s[j++]=st[i];
        s[j++]='$';
    }
    s[j]='&';
    return j;
}
void init(int len)
{
	for(int i = 0; i < 26; ++i) {
		last[len][i] = len;
	}
	for(int i = len - 1; i >= 0; --i) {
		for(int j = 0; j < 26; ++j) {
			last[i][j] = last[i + 1][j];
		}
		last[i][st[i] - 'a'] = i;
	}
}
LL Manacher()
{
	int len = change(), mid = 1, mx = 1;
	init(strlen(st));
	LL ans = 0;
	for (int i = 1; i < len; i++)
	{
		if (i < mx)
			p[i] = min(mx - i, p[mid * 2 - i]);
		else
			p[i] = 1;
		while (s[i - p[i]] == s[i + p[i]])
			p[i]++;
		if(mx < i + p[i])
		{
			mid = i;
			mx = i + p[i];
		}
	}
	int ori;
	for(int i = 1; i < len; ++i) {
		if(i & 1) 
			ori = (i + 1) / 2 - 1;
		else
			ori = i / 2 - 1;
		int cnt = p[i] / 2;
		for(int j = 0; j < 26; ++j) {
			if(last[ori][j] - ori < cnt) {
				ans += cnt - (last[ori][j] - ori);
			}
		}
	}
	return ans;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("input.in","r",stdin);
#endif
	scanf("%s",st);
	printf("%lld\n",Manacher());
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Sure, I'd be happy to give you some ideas for organizing a speech contest. Here are some suggestions: 1. Determine the theme and rules: Decide on the theme of the contest and the rules for participants. Will it be an open topic, or will there be a specific theme? What is the maximum length of the speech? Will there be any specific guidelines for language or content? 2. Decide on the judging criteria: Determine how the speeches will be evaluated. Will judges be looking for content, delivery, or both? Will there be a score sheet or rubric that judges will use to score the speeches? 3. Recruit judges: Find people who are qualified to judge the speeches. Ideally, they should have experience in public speaking or have a background in the theme of the contest. 4. Promote the contest: Advertise the contest to potential participants, such as students, professionals, or members of a specific community. Use social media, flyers, and other methods to get the word out. 5. Registration and selection: Set a deadline for registration and selection of participants. Consider having a preliminary round to narrow down the field before the final competition. 6. Prepare the venue: Ensure that the venue is suitable for the contest. Make sure that there is adequate seating, sound equipment, and lighting for the speakers. 7. Hold the contest: Set a date and time for the contest, and make sure that all participants and judges are aware of the schedule. Encourage audience participation and provide refreshments. 8. Award ceremony: After the contest, hold an award ceremony to recognize the winners and participants. Provide certificates or other prizes to the top performers. I hope these ideas help you in organizing a successful speech contest!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值