zoukankan      html  css  js  c++  java
  • 【UOJ #103】【APIO 2014】Palindromes

    http://uoj.ac/problem/103
    由manacher得:本质不同的回文串只有(O(n))个。
    用manacher求出所有本质不同的回文串,对每个本质不同的回文串,在后缀自动机的parent树上倍增求一下它出现了多少次,更新答案。
    时间复杂度(O(nlog n))

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    
    const int N = 300003;
    
    char s[N], r[N << 1];
    int n, tot = 0, top = -1, endtot = 0;
    
    struct State {
    	State *par, *go[26], *fa[21];
    	int val, sum;
    } *root, *last, pool[N << 2], *endpos[N];
    
    State *newState(int num) {
    	State *t = &pool[++top];
    	t->val = num;
    	t->par = 0; t->sum = 0;
    	memset(t->go, 0, sizeof(t->go));
    	return t;
    }
    
    void extend(int w) {
    	State *p = last;
    	State *np = newState(p->val + 1);
    	while (p && p->go[w] == 0)
    		p->go[w] = np, p = p->par;
    	if (p == 0) np->par = root;
    	else {
    		State *q = p->go[w];
    		if (q->val == p->val + 1) np->par = q;
    		else {
    			State *nq = newState(p->val + 1);
    			memcpy(nq->go, q->go, sizeof(q->go));
    			nq->par = q->par; q->par = np->par = nq;
    			while (p && p->go[w] == q)
    				p->go[w] = nq, p = p->par;
    		}
    	}
    	endpos[++endtot] = last = np;
    	last->sum = 1;
    }
    
    int len[N << 1], id[N << 2];
    
    ll cal(int t, int l) {
    	State *p = endpos[t];
    	for (int i = 20; i >= 0; --i)
    		if (p->fa[i]->val >= l)
    			p = p->fa[i];
    	return 1ll * p->sum * l;
    }
    
    bool cmp(int x, int y) {return pool[x].val < pool[y].val;}
    
    int main() {
    	scanf("%s", s + 1);
    	n = strlen(s + 1);
    	root = last = newState(0);
    	for (int i = 1; i <= n; ++i)
    		extend(s[i] - 'a');
    	
    	r[0] = '#';
    	for (int i = 1; i <= n; ++i) {
    		r[++tot] = '$';
    		r[++tot] = s[i];
    	}
    	r[++tot] = '$';
    	r[++tot] = '&';
    	
    	root->par = &pool[top + 1]; root->par->fa[0] = root->par; root->par->val = -1;
    	for (int i = 0; i <= top; ++i) pool[i].fa[0] = pool[i].par;
    	for (int j = 1; j <= 20; ++j)
    		for (int i = 0; i <= top + 1; ++i)
    			pool[i].fa[j] = pool[i].fa[j - 1]->fa[j - 1];
    	
    	for (int i = 0; i <= top; ++i) id[i] = i;
    	stable_sort(id, id + top + 1, cmp);
    	for (int i = top; i >= 0; --i)
    		pool[id[i]].par->sum += pool[id[i]].sum;
    	
    	ll ans = 0;
    	int cur = 0, pos; len[0] = 1;
    	for (int i = 1; i < tot; ++i) {
    		int &now = len[i]; pos = (cur << 1) - i; now = 0;
    		now = min(len[pos], cur + len[cur] - i); now = max(now, 0);
    		while (r[i - now] == r[i + now]) {
    			++now;
    			if ((i + now - 1) & 1) continue;
    			ans = max(ans, cal((i + now - 1) >> 1, now));
    		}
    		if (i + now > cur + len[cur]) cur = i;
    	}
    	
    	printf("%lld
    ", ans);
    	
    	return 0;
    }
    
  • 相关阅读:
    Android 学习笔记之WebService实现远程调用+内部原理分析...
    Android学习笔记之Json的使用....
    Android学习笔记之DocumentBuilder的使用....
    Android学习笔记之ExecutorService线程池的应用....
    Android学习笔记之SoftReference软引用...
    windows系统获取进程的pid号并终止
    Linux系统的时间比北京时间慢12个小时的处理方案(将EDT时区改为CST)
    将java的jar包作为windows的服务来启动
    linux初始化shell脚本
    linux中网络部分的总结
  • 原文地址:https://www.cnblogs.com/abclzr/p/6721456.html
Copyright © 2011-2022 走看看