捡金子 \operatorname{捡金子} 捡金子
题目链接: luogu T145308 \operatorname{luogu\ T145308} luogu T145308 / SSL比赛 1518 \operatorname{SSL比赛\ 1518} SSL比赛 1518
题目
从前有一个迷宫,迷宫的外形就像一棵带根树,每个结点(除了叶子结点外)恰好有 K K K 个儿子。
一开始你在根结点,根结点的 K K K 个儿子分别标记为 ‘A’, ‘B’, ‘C’…., 而结点 ‘A’ 的 K K K 个儿子结点分别标记为 ‘AA’,‘AB’,‘AC’…… ,依此类推。这棵树一共有 L L L 层。
现在你事先知道 M M M 个结点中有金子,并且你可以派出 N N N 个机器人去收集金子。首先你可以分别指定每一个机器人的目标结点,于是这些机器人就会收集从根结点到其目标结点这条路径上(包括目标结点)所有的金子,但是每个位置的金子只能被收集一次。
现在你需要制定一个目标的分配方案,使得收集到的金子最多。
输入
输入的第一行有 4 4 4 个整数: M , K , L , N M,K,L,N M,K,L,N 。对应题目描述中的参数。
接下来 M M M 行,每行是一个字符串,表示所对应的结点上有金子。
输出
输出利用 N N N 个机器人所能捡到时最多几个结点上的金子。
样例输入1
5 3 3 1
ACC
ACB
AB
AC
A
样例输出1
3
样例输入2
5 3 3 2
ACC
ACB
AB
AC
A
样例输出2
4
数据范围
对于 20 % 20\% 20% 的数据,有 1 ≤ M ≤ 20 1\le M\le 20 1≤M≤20 。
对于 40 % 40\% 40% 的数据,有 1 ≤ M ≤ 2000 1\le M\le 2000 1≤M≤2000 。
对于 100 % 100\% 100% 的数据,有 1 ≤ M ≤ 50000 , 1 ≤ K ≤ 26 , 1 ≤ L ≤ 50 , 1 ≤ N ≤ 10 1\le M\le 50000, 1\le K\le 26, 1\le L\le 50, 1\le N\le 10 1≤M≤50000,1≤K≤26,1≤L≤50,1≤N≤10 。
思路
这道题其实十分暴力,只是数据结构要用 Trie 树,我比赛的时候用 map 暴力都拿了 50 50 50 分。
至于什么是 Trie 树,最近应该会找时间做做模板题,写个博客。
如果我记得,写完那个博客我应该会放个链接在这里,如果不记得,可以直接我博客搜。
(不过肯定没人看QAQ )
就有点贪心吧,就每次找到路上金子最多的一条链,然后拿走,就这样跑 n n n 次,就可以得出答案了。
代码
#include<cstdio>
using namespace std;
int m, k, l, n, a[5000001][26], what[5000001], le[5000001];
int fa[5000001], last, K = 1, have[5000001];
int an[5000001], maxn, maxx, ans;
bool get[5000001];
char c;
int getnum(int now) {
//找到这一条链的金子数
if (now == 1 || get[fa[now]]) return have[now];
return have[now] + getnum(fa[now]);
}
void clear(int now) {
//把这一条链的金子拿掉
get[now] = 1;
if (now == 1 || get[fa[now]]) return ;
clear(fa[now]);
}
int main() {
scanf("%d %d %d %d", &m, &k, &l, &n);//读入
for (int i = 1; i <= m; i++) {
last = 1;
c = getchar();
while (c < 'A' || c > 'Z') c = getchar();//建Trie数
while (c >= 'A' && c <= 'Z') {
if (a[last][c - 'A']) last = a[last][c - 'A'];
else {
fa[++K] = last;
what[K] = c - 'A';
a[last][what[K]] = K;
last = K;
}
c = getchar();
}
have[last]++;
le[i] = last;
}
for (int times = 1; times <= n; times++) {
//每次删掉金子最多的链
maxn = 0;
for (int i = 1; i <= m; i++)
if (!get[le[i]]) {
an[i] = getnum(le[i]);
if (an[i] > maxn) {
maxn = an[i];
maxx = i;
}
}
clear(le[maxx]);
ans += maxn;//记录这条链拿了多少金子
}
printf("%d", ans);//输出
return 0;
}