P4683 [IOI 2008] Type Printer
题意
给 \(n\) 个长度不超过 \(20\) 的字符串,有一个奇妙的打印机,三种操作:在打印机当前词的末端(尾部)添加一个字母;在打印机当前词的尾部删去一个字母(将打印机当前词的最后一个字母删去)。仅当打印机当前至少有一个字母时才允许进行该操作;将打印机上的当前词打印出来。求按照任意顺序把 \(n\) 个字符串打印出来的最小操作次数,并给出一种方案。
序列的描述方法如下:
- 添加一个字母,用这个小写字母的自身来表示。
- 删去一个字母,用
-表示。 - 打印单词,用
P表示。
\(n\le2.5*10^4\)
思路
把字典树建出来,在上面 \(DFS\)。设当前在点 \(u\)。如果 \(u\) 是 \(g\) 个字符串的结尾,就输出 \(g\) 个 P。按照子树内最大深度从小到大遍历 \(u\) 的所有儿子,如果存在,就把该儿子对应的字符添加在末尾,向下递归,结束后把该字符删除。
现在得到了一个操作序列,但祂不是最优的,因为最后有很多删除,使得祂回到了原点。那么把序列末尾的 - 全部删除,直到出现第一个 P。由于在结束节点是先输出 P 再向下递归,并且遍历儿子时按照子树内最大深度从小到大遍历,最后输出的那个字符串一定是最长的一个字符串之一,使得节省的步数最大化,所以是最优的。
代码
// Problem: P4683 [IOI 2008] Type Printer
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4683
// Memory Limit: 62 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
namespace IO{
template<typename T>
inline void read(T&x){
x=0;char c=getchar();bool f=0;
while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
f?x=-x:0;
}
template<typename T>
inline void write(T x){
if(x==0){putchar('0');return ;}
x<0?x=-x,putchar('-'):0;short st[50],top=0;
while(x) st[++top]=x%10,x/=10;
while(top) putchar(st[top--]+'0');
}
inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
inline void write(char c){putchar(c);}
inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
const int maxn=25010;
int n;
vector<char>ans;
class Trie{
private:
struct node{
int ch[26];
char val,deep;
short end;
}t[maxn*20];
int cnt=1;
void dfs(int u){
if(u==0) return ;
t[u].deep=1;
for(int i=0;i<26;i++){
dfs(t[u].ch[i]);
t[u].deep=max<char>(t[u].deep,t[t[u].ch[i]].deep+1);
}
sort(t[u].ch,t[u].ch+26,[&](int a,int b){return t[a].deep<t[b].deep;});
}
void dfs2(int u){
if(u==0) return;
for(int i=1;i<=t[u].end;i++) ans.push_back('P');
for(int i=0;i<26;i++){
if(!t[u].ch[i]) continue;
ans.push_back(t[t[u].ch[i]].val);
dfs2(t[u].ch[i]);
ans.push_back('-');
}
}
public:
void insert(string s){
int u=1;
for(int i:s){
if(!t[u].ch[i-'a']) t[u].ch[i-'a']=++cnt,t[cnt].val=i;
u=t[u].ch[i-'a'];
}
t[u].end++;
}
void calc(){
dfs(1);
dfs2(1);
while(ans.back()=='-') ans.pop_back();
}
}tr;
signed main(){
read(n);
for(int i=1;i<=n;i++){
string s;read(s);
tr.insert(s);
}
tr.calc();
write(ans.size()),write("\n");
for(char i:ans) write(i),write("\n");
return 0;
}

浙公网安备 33010602011771号