zoukankan      html  css  js  c++  java
  • 【BZOJ 4567】【SCOI 2016】背单词

    http://www.lydsy.com/JudgeOnline/problem.php?id=4567
    贪心。
    任何不用第一种情况的方案吃的泡椒数都小于(n^2),所以最小泡椒数的方案一定不包含第一种情况。
    根据第二三种情况,正确的方案一定满足:一个字符串的所有后缀一定比它在表中先出现。
    所以可以对所有串建AC自动机,利用fail指针的后缀关系建出一棵树,树上的除了根外的每个点代表每个单词,根节点代表空单词。
    转化成了一个新问题:一棵n+1个节点的数,根节点编号为0,剩下的n个节点要分别编号为1~n,满足一个节点的编号比它父亲的编号小,要最小化(sumlimits_{u eq root}(id(u)-id(fa(u))))
    这也是一个贪心。
    直观地,每个子树内的点的编号一定是连续的,相当于一种dfs的顺序。
    对于一个子树的根r,r的所有孩子的dfs的顺序怎么确定?按r的孩子为根的子树大小排序就可以确定dfs顺序了。(直接用排序不等式证明——reflash)

    时间复杂度(O(|len|+nlog n))

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N = 510003;
    
    int n, ch[N][26], tot = 1, end[N], qu[N], fail[N], fail_far[N];
    
    void insert(char *s) {
    	int len = strlen(s), x, tmp = 1;
    	for (int i = 0; i < len; ++i) {
    		x = s[i] - 'a';
    		if (ch[tmp][x]) tmp = ch[tmp][x];
    		else tmp = ch[tmp][x] = ++tot;
    	}
    	end[tmp] = 1;
    }
    
    struct node {int nxt, to;} E[N];
    int cnt = 0, point[N], sz[N];
    void ins(int u, int v) {E[++cnt] = (node) {point[u], v}; point[u] = cnt;}
    
    void BFS() {
    	int p = 0, q = 1, f, u, v; qu[1] = 1; fail_far[1] = 1;
    	while (p != q) {
    		u = qu[++p];
    		for (int i = 0; i < 26; ++i)
    			if (v = ch[u][i]) {
    				f = fail[u];
    				while (f && ch[f][i] == 0) f = fail[f];
    				fail[v] = f ? ch[f][i] : 1;
    				if (end[v]) ins(fail_far[fail[v]], v);
    				fail_far[v] = end[v] ? v : fail_far[fail[v]];
    				qu[++q] = v;
    			}
    	}
    }
    
    ll ans = 0;
    char s[N];
    int a[N], nn;
    bool cmp(int x, int y) {return sz[x] < sz[y];}
    
    int dfs(int x) {
    	sz[x] = 1;
    	for (int i = point[x]; i; i = E[i].nxt) {
    		int v = E[i].to;
    		dfs(v);
    		sz[x] += sz[v];
    	}
    	
    	nn = 0;
    	for (int i = point[x]; i; i = E[i].nxt)
    		a[++nn] = E[i].to;
    	stable_sort(a + 1, a + nn + 1, cmp);
    	int sum = 1;
    	for (int i = 1; i <= nn; ++i)
    		ans += sum, sum += sz[a[i]];
    }
    
    int main() {
    	scanf("%d", &n);
    	int len;
    	for (int i = 1; i <= n; ++i) {
    		scanf("%s", s);
    		insert(s);
    	}
    	BFS();
    	dfs(1);
    	printf("%lld
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    使用 rabbitmq 的场景?
    什么是 Spring Cloud Bus?我们需要它吗?
    使用 Spring Cloud 有什么优势?
    我们如何监视所有 Spring Boot 微服务?
    什么是 YAML?
    如何集成 Spring Boot 和 ActiveMQ?
    什么是 JavaConfig?
    数据字典属于哪一个用户的?
    怎么对命令进行取别名?
    使用什么命令查看网络是否连通?
  • 原文地址:https://www.cnblogs.com/abclzr/p/6297261.html
Copyright © 2011-2022 走看看