[ SCOI 2016 ] 背单词

题目

Lougu
LOJ
Acwing

思路

1.png
2.png
3.png
4.png
5.png

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
const int N = 100010, M = 600010;
int n, tr[M][26], flag[M], idx_t;       // trie
string str[N];
int h[M], ptr[N], val[N], sz[M], idx_g; // 链式前向星
void insert(string str) {           
	int p = 0, c = str[0] - 'a';
	for (int i = 0; i < (int)str.size(); i++, c = str[i] - 'a')
		p = ((tr[p][c]) ? tr[p][c] : (tr[p][c] = ++idx_t));
	flag[p] = true; // 标记结尾
}
// 加边函数
void add(int a, int b) { val[idx_g] = b, ptr[idx_g] = h[a], h[a] = idx_g++; }
void update(int p, int top) {
    // 如果 v 是结尾,加边
	for (int i = 0; i < 26; i++) 
		if (flag[tr[p][i]]) add(top, tr[p][i]);
	for (int i = 0; i < 26; i++) 
		if (flag[tr[p][i]]) update(tr[p][i], tr[p][i]);
		else if (tr[p][i]) update(tr[p][i], top);
}
long long res = 0;
void DFS(int u) {
    // 计算子树大小
	sz[u] = 1;
	for (int i = h[u]; i != -1; i = ptr[i]) 
		DFS(val[i]), sz[u] += sz[val[i]];
	// 贪心计算答案
	vector<int> temp;
	for (int i = h[u]; i != -1; i = ptr[i])
		temp.push_back(sz[val[i]]);
	sort(temp.begin(), temp.end());
	int delta = 1; // 偏移量
	for (int i = 0; i < (int)temp.size(); i++)
		res += delta, delta += temp[i];
}
int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> str[i];
	for (int i = 1; i <= n; i++) reverse(str[i].begin(), str[i].end()); // 翻转
	for (int i = 1; i <= n; i++) insert(str[i]);                        // 插入
	memset(h, -1, sizeof h); 
	update(0, 0), DFS(0);
	cout << res << endl;		
	return 0;
}
posted @ 2021-04-13 16:36  Protein_lzl  阅读(51)  评论(0编辑  收藏  举报