Luogu P4683【IOI2008】Type Printer 印表機|trie
阿新 • • 發佈:2020-08-08
【IOI2008】Type Printer 印表機|trie
題意:一個印表機,支援向其加減一個字母和列印的操作。給出\(N\)個單詞,求列印這些單詞的最小運算元。注意,列印結束後允許印表機內有字母,且列印次序任意。
\(1\le N \le 25000\),單詞均小寫,最大長度20
分析:由於列印操作是無法省去的,運算元最小就要在加減字母下功夫。顯然若兩單詞有相同字首,則可以通過共用字首的方式解決。這樣可減少一次加減共兩個操作。
同時,由於最後一個單詞列印後可不刪除,因此最後一個單詞要儘量長。
根據相同字首這一條件,我們聯想到結構與此一致的trie,故使用Trie維護單詞。
可以證明,本題答案就是trie上節點個數*2(加,減各一次)+單詞數-最長單詞長度。
那麼接下來就是列印方案了,這裡採用將最後列印的單詞的節點最後遍歷,其他的先遍歷(顯然不影響答案),在遍歷到單詞的結束標記時列印的方式解決。
上程式碼
#include<bits/stdc++.h> using namespace std; int n,len,num,maxl,maxn,g,ans;string st[30000]; struct trie { int L[26];int e; }tree[901000]; void addtrie(int x,int y) { if (y==len) { tree[x].e=true; return ; } int ne=st[num][y]-'a'; if (!tree[x].L[ne]) { g++; tree[x].L[ne]=g; } addtrie(tree[x].L[ne],y+1); } void printrie(int x,int y,bool o) { int ne=0; if (!o) ne=26; else ne=st[maxn][y]-'a'; if (tree[x].e) cout<<"P\n"; for (int i=0;i<26;i++) { if (i==ne) continue; if (tree[x].L[i])//有就遍歷 { cout<<char(i+'a')<<endl; printrie(tree[x].L[i],y+1,0); cout<<"-\n"; } } if (o&&y!=maxl)//最後遍歷最長單詞 { cout<<char(ne+'a')<<endl; printrie(tree[x].L[ne],y+1,1); } } int main() { cin>>n; for (int i=1;i<=n;i++) { cin>>st[i]; num=i;len=st[i].size(); if (maxl<len) { maxl=max(maxl,len); maxn=i; } addtrie(0,0);//建trie } ans=g*2+n-maxl; cout<<ans<<endl; printrie(0,0,1); return 0; }
廣告Trie學習筆記