BZOJ 4567 [SCOI2016]背单词 (Trie树、贪心)

博客围绕Trie树问题展开,将字符串倒过来变成前缀建Trie后转化题意。最初提出按儿子个数从小到大选的贪心算法被证明错误,给出hack数据。正确方案是按子树大小从小到大选,并给出了相关证明。强调贪心算法不能想当然,一定要证明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=4567

题解: 显然答案一定小于\(n\times n\), 字符串倒过来变成前缀建Trie, 题意转化如下:

每次可以在一棵树上标记一个点,要求标记一个点之前所有祖先都标记过,标记一个点的价值等于它父亲被标记的时间,最大化价值和(也可以是求所有父子标记时间之差的和的最小值)

一看到这个脑子里立刻蹦出一个贪心: 按照儿子个数从小到大选(用堆维护)

然而是错的

hack数据:

10
aaa
baa
caa
daa
eaa
aa
a
b
ab
bb

正确的方案是按子树大小从小到大选。这里提供一个不知道对不对的证明(其实是拼凑网上的其他题解):

(1) 最优答案一定是DFS序。这个按照父子时间差之和来理解,挺显然。(抱歉我水平有限也就能说到这个份上了……)

(2) DFS序中的最优答案一定是按子树大小从小到大选。感性理解是: 由于是DFS序我们可以只考虑根对答案产生的贡献,最小化根与其所有儿子的时间差之和。然后就相当于有一堆数给他们排序使得前缀和的和最小,然后就显然了……

教训: 贪心这种东西千万不能想当然,一定要证明!要证明!要证明!

代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
#define llong long long
using namespace std;

const int N = 1e5;
const int L = 5e5+1e4;
const int S = 26;
struct Edge
{
    int v,nxt;
} e[(N<<1)+3];
int son[L+3][S+1];
char str[L+3];
bool isky[L+3];
int sz[N+3];
int sonn[N+3];
int fe[N+3];
int fa[N+3];
struct Element
{
    int u;
    Element() {}
    Element(int _u) {u = _u;}
    bool operator <(const Element &arg) const
    {
        return sz[u]>sz[arg.u];
    }
};
priority_queue<Element> que;
int n,siz,nn,en;

void insertstr(char str[],int len)
{
    int u = 1;
    for(int i=1; i<=len; i++)
    {
        if(!son[u][str[i]]) {siz++; son[u][str[i]] = siz;}
        u = son[u][str[i]];
    }
    isky[u] = true;
}

void addedge(int u,int v)
{
    printf("addedge %d %d\n",u,v);
    en++; e[en].v = v;
    e[en].nxt = fe[u]; fe[u] = en;
}

void dfs0(int u,int anc)
{
    if(isky[u]) {nn++; addedge(nn,anc); addedge(anc,nn); sonn[anc]++; anc = nn;}
    for(int i=1; i<=S; i++)
    {
        int v = son[u][i];
        if(v)
        {
            dfs0(v,anc);
        }
    }
}

void dfs(int u)
{
    sz[u] = 1;
    for(int i=fe[u]; i; i=e[i].nxt)
    {
        if(e[i].v==fa[u]) continue;
        fa[e[i].v] = u;
        dfs(e[i].v);
        sz[u] += sz[e[i].v];
    }
}

int main()
{
    siz = 1;
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        scanf("%s",str+1); int len = strlen(str+1);
        for(int j=1; j<=len; j++) str[j] -= 96;
        for(int j=1; j<=len+1-j; j++) swap(str[j],str[len+1-j]);
        insertstr(str,len);
    }
    nn = 1; dfs0(1,1);
    dfs(1);
    que.push(Element(1));
    llong ans = 0ll;
    for(int i=1; i<=nn; i++)
    {
        int u = que.top().u; que.pop();
        printf("%d\n",u);
        ans += sonn[u]*(i-1ll);
        for(int j=fe[u]; j; j=e[j].nxt)
        {
            if(e[j].v==fa[u]) continue;
            fa[e[j].v] = u;
            que.push(e[j].v);
        }
    }
    ans = n*(n+1ll)/2ll-ans;
    printf("%lld\n",ans);
    return 0;
}
资源下载链接为: https://pan.quark.cn/s/abbae039bf2a 无锡平芯微半导体科技有限公司生产的A1SHB三极管(全称PW2301A)是一款P沟道增强型MOSFET,具备低内阻、高重复雪崩耐受能力以及高效电源切换设计等优势。其技术规格如下:最大漏源电压(VDS)为-20V,最大连续漏极电流(ID)为-3A,可在此条件下稳定工作;栅源电压(VGS)最大值为±12V,能承受正反向电压;脉冲漏极电流(IDM)可达-10A,适合处理短暂高电流脉冲;最大功率耗散(PD)为1W,可防止器件过热。A1SHB采用3引脚SOT23-3封装,小型化设计利于空间受限的应用场景。热特性方面,结到环境的热阻(RθJA)为125℃/W,即每增加1W功率损耗,结温上升125℃,提示设计电路时需考虑散热。 A1SHB的电气性能出色,开关特性优异。开关测试电路及波形图(图1、图2)展示了不同条件下的开关性能,包括开关上升时间(tr)、下降时间(tf)、开启时间(ton)和关闭时间(toff),这些参数对评估MOSFET在高频开关应用中的效率至关重要。图4呈现了漏极电流(ID)与漏源电压(VDS)的关系,图5描绘了输出特性曲线,反映不同栅源电压下漏极电流的变化。图6至图10进一步揭示性能特征:转移特性(图7)显示栅极电压(Vgs)对漏极电流的影响;漏源开态电阻(RDS(ON))随Vgs变化的曲线(图8、图9)展现不同控制电压下的阻抗;图10可能涉及电容特性,对开关操作的响应速度和稳定性有重要影响。 A1SHB三极管(PW2301A)是高性能P沟道MOSFET,适用于低内阻、高效率电源切换及其他多种应用。用户在设计电路时,需充分考虑其电气参数、封装尺寸及热管理,以确保器件的可靠性和长期稳定性。无锡平芯微半导体科技有限公司提供的技术支持和代理商服务,可为用户在产品选型和应用过程中提供有
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值