Round A 2020 - Kick Start 2020 Bundling 字典树+贪心

本文介绍了一种使用字典树和深度优先搜索(DFS)算法解决特定字符串分组问题的方法。问题要求将给定的字符串集合划分成若干组,每组的价值为其所有字符串的最长公共前缀长度,目标是最大化那些恰好包含k个字符串的组的价值总和。通过构建字典树并记录每个节点的前缀数量和长度,文章详细阐述了如何遍历字典树以找到最优解。
摘要由CSDN通过智能技术生成

https://codingcompetitions.withgoogle.com/kickstart/round/000000000019ffc7/00000000001d3ff3
在这里插入图片描述在这里插入图片描述题目大意:每组数据给 n n n个字符串,每个字符串仅能划分到某一个组里面,且这个组的价值就等于该组所有字符串的最长公共前缀的长度。现在给一个数 k k k,让你给这些字符串划分组,使得所有刚好含有 k k k个字符串的组的价值之和最大。

思路:把这些字符串全部插到字典树里面,同时记录每个前缀的数量和长度,对于含有 k k k个字符串的一个组,因为它的价值和它们的最长公共前缀的长度有关系,贪心的想肯定要取最长的那个前缀。那么我们对字典树进行 d f s dfs dfs,设当前节点为 u u u,对它的所有子节点进行 d f s dfs dfs后,假设得到了一个值 s u m sum sum,表示 u u u的子节点中已经配对了 s u m sum sum个字符串,那么结合字典树的性质不难想到对于 u u u节点来说,可用的前缀只剩下 c n t [ u ] − s u m cnt[u]-sum cnt[u]sum个了,我们用这个数判断和 k k k的关系,更新答案即可。

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;

const int maxn=2e6+5;

int tot,ans,n,k;
char s[maxn];
int tree[maxn][26],cnt[maxn],len[maxn];

void Insert()
{
    int le=strlen(s);
    int rt=0;
    for(int i=0;i<le;i++)
    {
        if(!tree[rt][s[i]-'A'])
            tree[rt][s[i]-'A']=++tot;
        rt=tree[rt][s[i]-'A'];
        ++cnt[rt];
        len[rt]=i+1;
    }
}

int dfs(int u,int sum)
{
    for(int i=0;i<26;i++)
    {
        if(tree[u][i])
        {
            sum+=dfs(tree[u][i],0);
            tree[u][i]=0;
        }
    }
    int tmp=(cnt[u]-sum)/k;
    if(tmp)
    {
        ans+=tmp*len[u];
        sum+=tmp*k;
    }
    cnt[u]=len[u]=0;
    return sum;
}

int main()
{
    int t,times=0;
    scanf("%d",&t);
    while(t--)
    {
        tot=ans=0;
        scanf("%d%d",&n,&k);
        for(int i=0;i<n;i++)
        {
            scanf("%s",s);
            Insert();
        }
        dfs(0,0);
        printf("Case #%d: %d\n",++times,ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值