社区讨论
字典树做法,无需蓝以上证明
P1012[NOIP 1998 提高组] 拼数参与者 26已保存回复 43
讨论操作
快速查看讨论及其快照的属性,并进行相关操作。
- 当前回复
- 40 条
- 当前快照
- 1 份
- 快照标识符
- @mkp3i21p
- 此快照首次捕获于
- 2026/01/22 14:53 4 周前
- 此快照最后确认于
- 2026/01/22 20:29 4 周前
Code
CPP#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e3+5;
int tr[N][10];
pair<int,int> fa[N];
int ed[N];
int ans[N],tot;
int n,cnt=1;
void insert(char* s){
int l=strlen(s),p=1;
for(int i=0;i<l;i++){
int c=s[i]-'0';
if(!tr[p][c]) tr[p][c]=++cnt,fa[cnt]=make_pair(p,c);
p=tr[p][c];
}
ed[p]++;
return;
}
void erase(int p){
if(ed[p]>1){
ed[p]--;
return;
}
for(int i=0;i<10;i++)
if(tr[p][i]){
ed[p]--;
return;
}
ed[p]--;
while(!ed[p]&&p!=1){
int c=0;
for(int i=0;i<10;i++)
if(tr[p][i]) c++;
if(c) break;
tr[fa[p].first][fa[p].second]=0;
p=fa[p].first;
}
return;
}
void work(){
int p=1;
while(1){
int F=1;
while(!ed[p]){
int f=-1;
for(int c=9;c>=0;c--){
if(!tr[p][c]) continue;
ans[++tot]=c;
f=c;
p=tr[p][c];
F=0;
break;
}
// cout<<p<<'\n';
if(f==-1){
break;
}
}
if(F&&p!=1){
erase(p);
p=1;
continue;
}
if(F) break;
// cout<<p<<'\n';
int t1=1,t2=p;
while(1){
// cout<<t1<<' '<<t2<<'\n';
int c1=-1,c2=-1;
for(int c=9;c>=0;c--){
if(!tr[t1][c]) continue;
c1=c;
t1=tr[t1][c];
break;
}
for(int c=9;c>=0;c--){
if(!tr[t2][c]) continue;
c2=c;
t2=tr[t2][c];
break;
}
if(c2==-1){
erase(t2);
p=1;
break;
}
if(c1==c2){
ans[++tot]=c1;
continue;
}
if(c1>c2){
ans[++tot]=c1;
erase(p);
p=t1;
break;
}
if(c2>c1){
ans[++tot]=c2;
p=t2;
break;
}
}
}
return;
}
char a[20];
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a;
insert(a);
}
work();
for(int i=1;i<=tot;i++)
cout<<ans[i];
return 0;
}
建字典树。复杂度 。 为总长度。
从大到小便利,找到一个
end 后,用两个指针 t1 和 t2,分别从根和当前节点出发,找到第一个不同。- 若
t1指向大于t2:删除当前节点,使当前指向t1,继续该过程; - 若
t2指向大于t1:使当前指向t2,继续该过程; - 若
t2指向空,删除t2,使当前节点指向根,继续该过程。
中间
t1 和 t2 相同时直接加到答案里即可。欢迎 hack。
回复
共 43 条回复,欢迎继续交流。
正在加载回复...