1. 程式人生 > >P1481 魔族密碼

P1481 魔族密碼

小寫字母 n) string 一個 nlogn 有一個 統計 ron log

P1481 魔族密碼

題目描述

風之子剛走進他的考場,就……

花花:當當當當~~偶是魅力女皇——花花!!^^(華麗出場,禮炮,鮮花)

風之子:我嘔……(殺死人的眼神)快說題目!否則……-_-###

花花:……咦好冷我們現在要解決的是魔族的密碼問題(自我陶醉:搞不好魔族裏面還會有人用密碼給我和菜蟲寫情書咧,哦活活,當然是給我的比較多拉*^_^*)。魔族現在使用一種新型的密碼系統。每一個密碼都是一個給定的僅包含小寫字母的英文單詞表,每個單詞至少包含1個字母,至多75個字母。如果在一個由一個詞或多個詞組成的表中,除了最後一個以外,每個單詞都被其後的一個單詞所包含,即前一個單詞是後一個單詞的前綴,則稱詞表為一個詞鏈。例如下面單詞組成了一個詞鏈:

i int integer

但下面的單詞不組成詞鏈:

integer

intern 現在你要做的就是在一個給定的單詞表中取出一些詞,組成最長的詞鏈,就是包含單詞數最多的詞鏈。將它的單詞數統計出來,就得到密碼了。

風之子:密碼就是最長詞鏈所包括的單詞數阿……

花花:活活活,還有,看你長得還不錯,給你一個樣例吧:

輸入輸出格式

輸入格式:

這些文件的格式是,第一行為單詞表中的單詞數N(1<=N<=2000),下面每一行有一個單詞,按字典順序排列,中間也沒有重復的單詞咧!!

輸出格式:

你要提交的文件中只要在第一行輸出密碼就行啦^^

輸入輸出樣例

輸入樣例#1:
5
i
int
integer
intern
internet
輸出樣例#1:
4

說明

DP LIS

分析:

思路易得,LIS

說一個O(nlogn)的算法;

維護單調棧+二分,棧的長度即為最大公共子序列的長度

入棧操作:

1)若將要進棧的元素包含棧中最大元素,進棧並儲存在最後一個位置,top++。

2)否則,找到第一個不被將要進棧的元素包含的位置,將其替換成將要進棧的元素,這部分由二分完成

說明:這個題目是字典序,才能這麽做,自己想想,想不懂的看下面樣例的演示過程:

樣例:

7
i
int
integer
intern
internet
intexl
intexlm

樣例的棧演示過程:

技術分享

代碼:

 1 #include<iostream>
 2
#include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<iomanip> 6 using namespace std; 7 int n; 8 string a[10002]; 9 string stack[10002]; 10 int ans=0; 11 void print(string (&s)[10002],int top){ 12 for(int i=0;i<=top;i++) cout<<setw(12)<<s[i]; 13 cout<<endl; 14 } 15 int main(){ 16 freopen("in.txt","r",stdin); 17 scanf("%d",&n); 18 int top; 19 stack[0]=""; 20 top=0; 21 for(int i=1;i<=n;i++){ 22 cin>>a[i]; 23 if(a[i].find(stack[top])==0){ 24 stack[++top]=a[i]; 25 } 26 else{ 27 int l=1,r=top; 28 while(l<=r){ 29 int mid=(l+r)/2; 30 if(a[i].find(stack[mid])==0) l=mid+1; 31 else r=mid-1; 32 } 33 stack[l]=a[i]; 34 } 35 ans=max(ans,top); 36 print(stack,top); 37 } 38 printf("%d",ans); 39 return 0; 40 }

P1481 魔族密碼