bzoj4567 背單詞
阿新 • • 發佈:2018-10-06
== getchar ets esc pre desc 記錄 iostream trie樹
輸入一個整數 n ,表示 Lweb 要學習的單詞數。接下來 n 行,每行有一個單詞(由小寫字母構成,且保證任意單
詞兩兩互不相同)1≤n≤100000, 所有字符的長度總和 1≤|len|≤510000
a
ba
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 個單詞的情況下,吃最少的泡椒。Input
Output
Lweb 吃的最少泡椒數
Sample Input
2a
ba
Sample Output
2 這道題的題目意思是:給你n個字符串,不同的排列有不同的代價,代價按照如下方式計算(字符串s的位置為x):
1.排在s後面的字符串有s的後綴,則代價為n^2;
2.排在s前面的字符串有s的後綴,且沒有排在s後面的s的後綴,則代價為x-y(y為最後一個與s不相等的後綴的位置);
3.s沒有後綴,則代價為x。
根據後綴的條件,我們可以判斷出這道題可以用trie樹。當然我們需要反向存字符串。
然後我們可以知道,對於一個字符串,只有它的第一個點(翻轉之前)是對我們有用的,比如:ABCD,BCD我們只用記錄A有一條向B的邊。
我們先正常建樹,然後標記所有末尾點,如果這個點的父親是它的前綴,那麽就連一條父親到他的邊。
對於取字符策略,考慮貪心。對於一個點,我們優先選擇那個最小的子樹,從小到大,依次枚舉。
#include <iostream> #include <cstdlib> #include <cstdio> #include<cstring> #include <algorithm> #define REP(i,k,n) for(long long i=k;i<=n;i++) #define in(a) a=read() #define MAXN 510010 using namespace std; inline long long read(){ long long x=0,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch==‘-‘) f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-‘0‘; return x*f; } long long n; long long cnt=1; long long f[MAXN]; long long total=0,head[MAXN],nxt[MAXN],to[MAXN]; long long tree[MAXN][26],isend[MAXN]; long long size[MAXN]; long long dfn[MAXN],ind=0,ans=0; long long top=0; struct node{ long long si,in; }arr[MAXN]; inline void adl(long long a,long long b){ total++; // cout<<total<<" "<<a<<" "<<b<<endl; to[total]=b; nxt[total]=head[a]; head[a]=total; return ; } inline void insert(char *s){ long long u=1; for(long long i=strlen(s)-1;i>=0;i--){ if(!tree[u][s[i]-‘a‘]) tree[u][s[i]-‘a‘]=++cnt; u=tree[u][s[i]-‘a‘]; } //cout<<u<<endl; isend[u]=1; return ; } inline void build(long long u,long long f){ if(isend[u]){ adl(f,u); f=u; } REP(i,0,25) if(tree[u][i]) build(tree[u][i],f); return ; } inline void getsize(long long u){ size[u]=1; for(long long e=head[u];e;e=nxt[e]){ getsize(to[e]); size[u]+=size[to[e]]; } return ; } inline bool cmp(node a,node b){ return a.si<b.si; } inline void getans(long long u){ dfn[u]=++ind; long long m=top+1; for(long long e=head[u];e;e=nxt[e]){ arr[++top].in=to[e]; arr[top].si=size[to[e]]; } if(top<m) return ; sort(arr+m,arr+top+1,cmp); REP(i,m,top){ getans(arr[i].in); ans+=dfn[arr[i].in]-dfn[u]; //cout<<u<<" "<<arr[i].in<<" "<<ans<<endl; } top=m-1; return ; } int main(){ in(n); char c[100010]; REP(i,1,n){ scanf("%s",c); insert(c); } build(1,1); getsize(1); getans(1); cout<<ans; } /* 4 da dcba ba cba */
bzoj4567 背單詞