1. 程式人生 > >bzoj 4567: [Scoi2016]背單詞

bzoj 4567: [Scoi2016]背單詞

沒有 ace fin lib down ring name 而且 cst

Description

Lweb 面對如山的英語單詞,陷入了深深的沈思,“我怎麽樣才能快點學完,然後去玩三國殺呢?”。這時候睿智
的鳳老師從遠處飄來,他送給了 Lweb 一本計劃冊和一大缸泡椒,他的計劃冊是長這樣的:
—————
序號 單詞
—————
1
2
……
n-2
n-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 個單詞的情況下,吃最少的泡椒。

Solution

正解:trie樹+貪心
顯然情況1是需要盡量不發生的,而且是可以避免的,只要把它的後綴都先加入即可
因為有相同後綴的要盡量在一起,所以在trie樹上也就是連續一段,一直走即可
考慮到從一個節點往子樹走的順序只會影響到 父親為該節點的兒子,所以滿足局部最優,只要每次先走最小的子樹即可.

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std; typedef long long ll; const int N=510005; int n,cnt=0,sz[N],ch[N][27],w[N];char s[N]; inline void ins(){ scanf("%s",s); int len=strlen(s),p=0; for(int i=len-1;i>=0;i--){ int x=s[i]-'a'; if(!ch[p][x])ch[p][x]=++cnt; p=ch[p][x]; } w[p]++; } struct node{ int x,v; bool operator <(const node &pr)const{return v>pr.v;} }; int head[N],nxt[N*26],to[N*26],num=0; inline void link(int x,int y){ nxt[++num]=head[x];to[num]=y;head[x]=num; } int id=0;ll ans=0; inline void dfs(int x,int last){ int now=0; if(x)id++,ans+=id-last,now=id; priority_queue<node>q; for(int i=head[x];i;i=nxt[i]) if(to[i])q.push((node){to[i],sz[to[i]]}); while(!q.empty()){ int u=q.top().x;q.pop(); dfs(u,now); } } inline void build(int x,int last){ if(w[x])link(last,x); for(int i=0;i<=25;i++){ int u=ch[x][i]; if(u)build(u,w[x]?x:last); } } inline void getit(int x){ sz[x]=1; for(int u,i=head[x];i;i=nxt[i]) u=to[i],getit(u),sz[x]+=sz[u]; } void work() { scanf("%d",&n); for(int i=1;i<=n;i++)ins(); build(0,0);getit(0); dfs(0,0); cout<<ans<<endl; } int main() { freopen("pp.in","r",stdin); freopen("pp.out","w",stdout); work(); return 0; }

bzoj 4567: [Scoi2016]背單詞