bzoj 4567: [Scoi2016]背單詞
阿新 • • 發佈:2017-12-25
沒有 ace fin lib down ring name 而且 cst
椒就能記住它;
3) 當它的所有後綴都被填入表內的情況下,如果 1...x-1的位置上存在是它後綴的單詞,所有是它後綴的單詞中
,序號最大為 y ,那麽你只要吃 x-y 顆泡椒就能把它記住。
Lweb 是一個吃到辣辣的東西會暴走的奇怪小朋友,所以請你幫助 Lweb ,尋找一種最優的填寫單詞方案,使得他
記住這 n 個單詞的情況下,吃最少的泡椒。
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]背單詞