LibreOJ #2012. 「SCOI2016」背单词

二次联通门 : LibreOJ #2012. 「SCOI2016」背单词

/*
    LibreOJ #2012. 「SCOI2016」背单词 

    Trie + 贪心

    大家都吐槽题目反人类
    可我觉得还好,毕竟见的多了

    不会做啊。。
    正解好巧妙

    考虑一下,发现一操作完全不必要,可以省去
    因为所有的字符串的后缀关系会形成一个树

    那么把字符串倒序插入Trie中
    建树,每次向子树小的一个点转移即可
*/
#include <cstdio>
#include <algorithm>
#include <cstring>
#define Max 100008
#define L 26
int N;
char line[Max];

int trie[Max][L], T_C = 1;
bool is[Max];
struct E
{
    E *n; int to;
};
E *list[Max], poor[Max], *Ta = poor;
void Dfs (int now, int Father)
{
    if (is[now])
    {
        ++ Ta, Ta->to = now, Ta->n = list[Father], list[Father] = Ta;
        Father = now;
    }
    for (int i = 0; i < L; ++ i)
        if (trie[now][i])
            Dfs (trie[now][i], Father);
}
int size[Max];

void Re_Dfs (int now)
{
    size[now] = 1;
    for (E *e = list[now]; e; e = e->n)
        Re_Dfs (e->to), size[now] += size[e->to];
}
int dfn[Max], top, C, Stack[Max], Answer;
inline bool Comp (int a, int b)
{
    return size[a] < size[b];
}
void Get_Answer (int now)
{
    dfn[now] = ++ C; int pos = top + 1;
    for (E *e = list[now]; e; e = e->n)
        Stack[++ top] = e->to;
    if (top < pos) return ;
    std :: sort (Stack + pos, Stack + top + 1, Comp);
    for (int i = pos; i <= top; ++ i)
        Get_Answer (Stack[i]), Answer += dfn[Stack[i]] - dfn[now];
    top = pos - 1;
}

int Main ()
{
    scanf ("%d", &N); register int i, j;
    int Id, x, now, Len;
    for (i = 1; i <= N; ++ i)
    {
        scanf ("%s", line); Len = strlen (line);
        for (j = Len - 1, now = 1; j >= 0; -- j)
        {
            Id = line[j] - ‘a‘;
            if (trie[now][Id] == 0)
                trie[now][Id] = ++ T_C;
            now = trie[now][Id];
        }
        is[now] = true;
    }
    Dfs (1, 1), Re_Dfs (1), Get_Answer (1);
    printf ("%d", Answer);
    return 0;
}
int ZlycerQan = Main ();
int main (int argc, char *argv[]) {;}
时间: 2024-12-24 18:24:45

LibreOJ #2012. 「SCOI2016」背单词的相关文章

AC日记——「SCOI2016」背单词 LiBreOJ 2012

#2012. 「SCOI2016」背单词 思路: Orz: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #define maxm 510005 int n,ch[maxm][26],tot=1,len,head[maxm],E[maxm],V[maxm],cnt=1; int val[maxm],cnt2,size[maxm],sta[maxm],top; long long ans,sum; ch

LibreOJ #2016. 「SCOI2016」美味

二次联通门 : LibreOJ #2016. 「SCOI2016」美味 /* LibreOJ #2016. 「SCOI2016」美味 dalao们都在说这题如果没有加法balabala就可以用可持久化trie解决了 然而我连那个也不会啊QAQ 此题用主席树 从高位到低位贪心 能填1就填1,也就是查询一段区间有没有某个范围的数 (然而由乃dalao说可持久化线段树和可持久化trie是一个东西) */ #include <cstdio> #include <iostream> #inc

LibreOJ #2013. 「SCOI2016」幸运数字

二次联通门 : LibreOJ #2013. 「SCOI2016」幸运数字 /* LibreOJ #2013. 「SCOI2016」幸运数字 树链剖分 + 线段树 + 线性基合并 没什么可说的 对原树进行树链剖分 然后建线段树 每个区间维护一段线性基 每次暴力把一段插入另一段中 最后线性基求最大即可 注意线性基求最大时一定是倒着枚举的 */ #include <cstdio> #include <iostream> const int BUF = 12312334; char Bu

LibreOJ #2006. 「SCOI2015」小凸玩矩阵

二次联通门 : LibreOJ #2006. 「SCOI2015」小凸玩矩阵 /* LibreOJ #2006. 「SCOI2015」小凸玩矩阵 本来以为是道数据结构题 后来想了想发现不可做 就考虑二分dp判断 推方程推不出来 就考虑用网络流判断了 二分出一个数 将小于这个数的位置的点编号 每行的可行点与下一行可行的点连边 后一边最大流判断可选出的数的个数是否符合要求即可 */ #include <cstdio> #include <iostream> #include <q

LibreOJ #2002. 「SDOI2017」序列计数

二次联通门 : LibreOJ #2002. 「SDOI2017」序列计数 /* LibreOJ #2002. 「SDOI2017」序列计数 线性筛 + 矩阵优化dp 先构造出全部情况的矩阵 用矩阵快速幂计算答案 再构造出全不是质数的矩阵 计算出答案 前一个答案减后一个答案即可 */ #include <cstdio> #include <iostream> #include <cstring> const int BUF = 12312312; char Buf[BU

LibreOJ #2033. 「SDOI2016」生成魔咒

二次联通门 : LibreOJ #2033. 「SDOI2016」生成魔咒 /* LibreOJ #2033. 「SDOI2016」生成魔咒 调了整整一天啊... 绝望啊 最后发现是1打成i了啊!!! */ #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <map> const int BUF = 10000020; char

LibreOJ #2061. 「HAOI2016」放棋子

二次连通门 : LibreOJ #2061. 「HAOI2016」放棋子 /* LibreOJ #2061. 「HAOI2016」放棋子 MDZZ ... 错排 + 高精 */ #include <iostream> #include <cstdio> #include <vector> #include <iomanip> #include <cassert> #include <algorithm> #define int64 l

LibreOJ #2219. 「HEOI2014」大工程

二次联通门 : LibreOJ #2219. 「HEOI2014」大工程 /* LibreOJ #2219. 「HEOI2014」大工程 虚树 + dp 对于每次的关键点建好虚树后 考虑树形dp dp[i] 表示在以i为根的子树路径总长 size[i] 表示在以i为根的子树中关键点的个数 maxn为以i为根的子树中到关键点到根最长的路径长 ans1自己推一推就好 对于ans2 如果i是关键点,则直接用maxn[i]更新答案 否则用maxn[i]+maxn[child[i]]+dis(i,son[

LibreOJ #2007. 「SCOI2015」国旗计划

二次联通门 : LibreOJ #2007. 「SCOI2015」国旗计划 --by Claris /* LibreOJ #2007. 「SCOI2015」国旗计划 跪膜Claris... */ #include <cstdio> #include <iostream> #include <algorithm> const int BUF = 12312312; char Buf[BUF], *buf = Buf; inline void read (int &