[luogu3294][背单词]

题目链接

题意

读完题目就一个感受:这出题人tm不会说人话吗。真的感觉这个题理解题意比想出正解更难。
其实题目的意思就是,给出一些单词,给这些单词编个号,然后要求其他的单词中是这个单词后缀的词都在这个词的前面。每个单词的贡献是当前单词的标号减去他的后缀中标号最大的那个的标号。
希望我能表达明白吧233

思路

因为后缀不好考虑,所以先把字符串倒过来,就都变成了前缀
然后把这些字符串在全都挂到trie树上,每个字符串的结尾打的标记是这个字符串的标号。
删去trie树中的虚点(没有打标记的点)。就可以得到一棵新的树,然后发现,每个字符串的前缀肯定都是他的祖先。然后要求给这些节点编号,是的每个节点的祖先的编号都比这个节点的编号小。并且使得所有节点的编号与他父亲的编号的差值和最小。
用贪心的思想,先给子树大小最小的那棵子树编号。显然这样贪心是对的。

代码

/*
* @Author: wxyww
* @Date:   2018-12-17 11:02:04
* @Last Modified time: 2018-12-17 16:59:58
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<ctime>
#include<bitset>
using namespace std;
typedef long long ll;
const int N  = 110000;
ll read() {
   ll x=0,f=1;char c=getchar();
   while(c<'0'||c>'9') {
      if(c=='-') f=-1;
      c=getchar();
   }
   while(c>='0'&&c<='9') {
      x=x*10+c-'0';
      c=getchar();
   }
   return x*f;
}
vector<int>e[N];
int trie[N * 5][30];
char s[N * 5];
int siz[N * 5],tot,bz[N * 5];
void insert(int k) {
   int len = strlen(s + 1);
   int now = 0;
   for(int i = len;i >= 1;--i) {
      if(!trie[now][s[i] - 'a']) trie[now][s[i] - 'a'] = ++tot;
      now = trie[now][s[i] - 'a'];
   }
   bz[now] = k;
}
void dfs1(int u,int fa) {
   if(bz[u]) e[fa].push_back(bz[u]);
   for(int i = 0;i < 26;++i) {
      if(!trie[u][i]) continue;
      if(bz[u]) dfs1(trie[u][i],bz[u]);
      else dfs1(trie[u][i],fa);
   }
}
bool cmp(int x,int y) {
   return siz[x] < siz[y];
}
void dfs2(int u) {
   int k = e[u].size();
   siz[u] = 1;
   for(int i = 0;i < k;++i) {
      int v = e[u][i];
      dfs2(v);
      siz[u] += siz[v]; 
   }
   sort(e[u].begin(),e[u].end(),cmp);
}
int now,bh[N];
ll ans;
void solve(int u,int fa) {
   ans += now - fa;fa = now ++;
   int k = e[u].size();
   for(int i = 0;i < k;++i) {
      int v = e[u][i];
      solve(v,fa);
   }
}

int main() {
   int n = read();
   for(int i = 1;i <= n;++i) {
      scanf("%s",s + 1);    
      insert(i);
   }
   dfs1(0,0);
   dfs2(0);
   solve(0,0);
   cout<<ans;
   return 0;
}

一言

书足以记名姓而已。剑一人敌,不足学,学万人敌。

全部评论

相关推荐

刚刷到字节跳动官方发的消息,确实被这波阵仗吓了一跳。在大家还在纠结今年行情是不是又“寒冬”的时候,字节直接甩出了史上规模最大的转正实习计划——ByteIntern。咱们直接看几个最硬的数,别被花里胡哨的宣传词绕晕了。首先是“量大”。全球招7000多人是什么概念?这几乎是把很多中型互联网公司的总人数都给招进来了。最关键的是,这次的资源分配非常精准:研发岗给了4800多个Offer,占比直接超过六成。说白了,字节今年还是要死磕技术,尤其是产品和AI领域,这对于咱们写代码的同学来说,绝对是今年最厚的一块肥肉。其次是大家最关心的“转正率”。官方直接白纸黑字写了:整体转正率超过50%。这意味着只要你进去了,不划水、正常干,每两个人里就有一个能直接拿校招Offer。对于2027届(2026年9月到2027年8月毕业)的同学来说,这不仅是实习,这简直就是通往大厂的快捷通道。不过,我也得泼盆冷水。坑位多,不代表门槛低。字节的实习面试出了名的爱考算法和工程实操,尤其是今年重点倾斜AI方向,如果你简历里有和AI相关的项目,优势还是有的。而且,转正率50%也意味着剩下那50%的人是陪跑的,进去之后的考核压力肯定不小。一句话总结:&nbsp;27届的兄弟们,别犹豫了。今年字节这是铁了心要抢提前批的人才,现在投递就是占坑。与其等到明年秋招去千军万马挤独木桥,不如现在进去先占个工位,把转正名额攥在手里。
喵_coding:别逗了 50%转正率 仔细想想 就是转正与不转正
字节7000实习来了,你...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务