• BZOJ4516[SDOI2016]生成魔咒(后缀数组/后缀自动机)


    题目链接

    洛谷

    BZOJ

    前置知识

    后缀数组后缀自动机

    前一个百度即可查获大量资料

    后一个推荐hihocoder上的全套教程,题库搜索“后缀自动机”即可找到

    解析

    方法一:后缀数组

    链接大法:https://blog.csdn.net/A_Comme_Amour/article/details/79987498

    方法二:后缀自动机

    回想构建后缀自动机的过程,不难发现每增加一个字符,增加的本质不同的子串就是(new\_node->maxlen - new\_node->link->maxlen)

    而拆出来的点是不产生贡献的

    构建自动机过程中统计答案即可

    代码(后缀自动机)

    学了3次后缀自动机,放个板子在这里以免又忘。。。。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <map>
    #define MAXN 100005
    
    typedef long long LL;
    struct SuffixAutomaton {
    	struct Node {
    		Node *link;
    		std::map<int, Node *> next;
    		int maxlen;
    	} * root, *last;
    	LL ans;
    	SuffixAutomaton() { last = root = new Node(); }
    	Node *add(int);
    	void build(int *, int);
    } sam;
    int N, a[MAXN], hash[MAXN], tot;
    
    char gc();
    LL read();
    void print(LL);
    void println(LL);
    int main() {
    	N = read();
    	for (int i = 0; i < N; ++i)
    		a[i] = read();
    	sam.build(a, N);
    }
    inline char gc() {
    	static char buf[1000000], *p1, *p2;
    	if (p1 == p2) p1 = (p2 = buf) + fread(buf, 1, 1000000, stdin);
    	return p1 == p2 ? EOF : *p2++;
    }
    inline LL read() {
    	LL res = 0; char ch = gc();
    	while (ch < '0' || ch > '9') ch = gc();
    	while (ch >= '0' && ch <= '9')
    		res = (res << 1) + (res << 3) + ch - '0', ch = gc();
    	return res;
    }
    inline void print(LL x) {
    	static int buf[30];
    	if (!x) putchar('0');
    	else {
    		while (x) buf[++buf[0]] = x % 10, x /= 10;
    		while (buf[0]) putchar('0' + buf[buf[0]--]);
    	}
    }
    inline void println(LL x) { print(x); putchar('
    '); }
    SuffixAutomaton::Node *SuffixAutomaton::add(int c) {
    	Node *np = new Node(), *p = last;
    	np->maxlen = last->maxlen + 1;
    	while (p && !p->next.count(c)) p->next[c] = np, p = p->link;
    	if (!p) np->link = root;
    	else {
    		Node *q = p->next[c];
    		if (q->maxlen == p->maxlen + 1) np->link = q;
    		else {
    			Node *nq = new Node();
    			nq->link = q->link, nq->maxlen = p->maxlen + 1, nq->next = q->next;
    			q->link = np->link = nq;
    			while (p && p->next[c] == q) p->next[c] = nq, p = p->link;
    		}
    	}
    	return np;
    }
    void SuffixAutomaton::build(int *arr, int size) {
    	for (int i = 0; i < size; ++i) last = add(arr[i]), println(ans = ans + last->maxlen - last->link->maxlen);
    }
    
  • 相关阅读:
    类别category 总结
    autorelease理解
    NSAutoreleasePool drain release的区别
    ios 文件管理 目录
    关于autorelease pool一个较好的理解
    iOS中四种实例变量的范围类型@private@protected@public@package
    批量删除
    会话用法 和留言板例题
    运用php做投票题,例题
    php 封装
  • 原文地址:https://www.cnblogs.com/Rhein-E/p/10445032.html
Copyright © 2020-2023  润新知