题目描述
Lweb 面对如山的英语单词,陷入了深深的沉思,”我怎么样才能快点学完,然后去玩三国杀呢?“。这时候睿智的凤老师从远处飘来,他送给了 Lweb 一本计划册和一大缸泡椒,他的计划册是长这样的:
—————序号 单词—————
1 2......n-2n-1 n—————
然后凤老师告诉 Lweb ,我知道你要学习的单词总共有 n 个,现在我们从上往下完成计划表,对于一个序号为 x 的单词(序号 1...x-1 都已经被填入):
1) 如果存在一个单词是它的后缀,并且当前没有被填入表内,那他需要吃 n*n 颗泡椒才能学会;
2) 当它的所有后缀都被填入表内的情况下,如果在 1...x-1 的位置上的单词都不是它的后缀,那么你吃 x 颗泡椒就能记住它;
3) 当它的所有后缀都被填入表内的情况下,如果 1...x-1的位置上存在是它后缀的单词,所有是它后缀的单词中,序号最大为 y ,那么你只要吃 x-y 颗泡椒就能把它记住。
Lweb 是一个吃到辣辣的东西会暴走的奇怪小朋友,所以请你帮助 Lweb ,寻找一种最优的填写单词方案,使得他记住这 n 个单词的情况下,吃最少的泡椒。
--by luogu
http://daniu.luogu.org/problem/show?pid=3294
不是很懂四川人对泡椒的热情;
倒置单词,然后建trie
首先可以肯定第一种情况不存在;
看一眼trie树发现只要按trie背单词总不会有情况一
用trie树建立一棵表示单词后缀关系的新树;
(相当于把没有is_end标记的点缩去)
然后有两个性质:
1,背完整棵子树再背其他;
2,先背小的子树;
暴力排序并dfs即可;
(upd:泡椒真尼玛好吃)
代码如下:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 struct ss{ 6 int next,to; 7 }tree[100010]; 8 int first[100010],num,size[100010]; 9 int sor[100010],dfn[100010]; 10 struct Trie{ 11 int ch[26]; 12 int flag; 13 }; 14 Trie trie[510010]; 15 int tot,n; 16 char s[510010]; 17 long long ans=0; 18 int dfs_1(int ,int ); 19 void build(int ,int ); 20 void dfs_2(int ,int ,int ); 21 bool cmp(int ,int ); 22 int main() 23 { 24 int i,j,k,len;; 25 scanf("%d",&n); 26 for(i=1;i<=n;i++){ 27 scanf("%s",s); 28 len=strlen(s); 29 k=0; 30 for(j=len-1;j>=0;j--){ 31 if(!trie[k].ch[s[j]-'a']) 32 trie[k].ch[s[j]-'a']=++tot; 33 k=trie[k].ch[s[j]-'a']; 34 } 35 trie[k].flag=1; 36 } 37 n=0; 38 dfs_1(0,1);num=0; 39 dfs_2(1,1,0); 40 printf("%lld ",ans); 41 return 0; 42 } 43 int dfs_1(int now,int fa){ 44 int j=0,k; 45 if(trie[now].flag||now==0)k=++n; 46 for(int i=0;i<=25;i++) 47 if(trie[now].ch[i]) 48 j+=dfs_1(trie[now].ch[i],trie[now].flag?k:fa); 49 if(trie[now].flag&&now) 50 size[k]=++j,build(fa,k); 51 return j; 52 } 53 void build(int f,int t){ 54 tree[++num].next=first[f]; 55 tree[num].to=t; 56 first[f]=num; 57 } 58 void dfs_2(int now,int fa,int str){ 59 int i,j=str,k; 60 dfn[now]=++num; 61 ans+=dfn[now]-dfn[fa]; 62 for(i=first[now];i;i=tree[i].next) 63 sor[++j]=i; 64 sort(sor+str+1,sor+j+1,cmp); 65 for(i=str+1;i<=j;i++){ 66 dfs_2(tree[sor[i]].to,now,j); 67 } 68 } 69 bool cmp(int a,int b){ 70 return size[tree[a].to]<size[tree[b].to]; 71 }