选拔比赛的时候没有写出来,下来看了下是字典树,就把字典树 学了,这应该算是我学的第三个字符串算法,他的题型也很有特点。
KMP和哈希就是严格的两个字符串比较,而字典树就是一个字符串和对其他全部字符串同时进行处理,好像也只能把所有字符串映射到一张图上了。总之输入多了或影响大了可以往字典树考虑
回归正题,思路:
将所有的数分解为18位(建议字符串输入),从高位到低位依次建立字典树。
可以全部数 更新完毕后再查找(另一个不能找到自己,比较麻烦)。也可以先找该点最大的最小的,再去更新该数,因为答案是一对的,先进的搜不到后进的,但后进的可以搜到先进的,答案是不变的,用的时间会更少
每次选择一个数进行查找,比如这个数是000004234求最小,前面的0每次都优先选择0,依次选择1,2,3,4···9,。4可以优先选择6,7,8,9···3,可以通过%10实现这个数字的选择。
min,max答案即可
代码:
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
#include<utility>
#include<vector>
#include<bits/stdc++.h>
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define inf 0x3f3f3f3f
#define ll long long
#define M 1000005
#define len 19
int t,n,l,cnt=0;
ll minn=(ll)inf*inf,maxx=0,P[20]={1};
char s[20];
int trie[M*20][12];
inline void query_minn(){
int p=0;
ll sum=0;
for(int i=len-1;i>=0;i--){
int c=(i>=l)?0:s[i]-'0';
for(int j=10-c;j<20-c;j++){
if(trie[p][(j%10)]){
p=trie[p][(j%10)];
sum+=P[i]*((c+j)%10);
break;
}
}
}
minn=min(sum,minn);
}
inline void query_maxx(){
int p=0;
ll sum=0;
for(int i=len-1;i>=0;i--){
int c=(i>=l)?0:s[i]-'0';
for(int j=20-c-1;j>10-c-1;j--){
if(trie[p][(j%10)]){
p=trie[p][(j%10)];
sum+=P[i]*((c+j)%10);
break;
}
}
}
maxx=max(sum,maxx);
}
inline void add(){
int p=0;
for(int i=len-1;i>=0;i--){
int c=0;
if(i>=l) c=0;
else c=s[i]-'0';
if(!trie[p][c]) trie[p][c]=++cnt;
p=trie[p][c];
}
}
int main(){
fo(1,len-1) P[i]=P[i-1]*10;
scanf("%d",&n);
fo(1,n){
scanf("%s",s);
l=strlen(s);
reverse(s,s+l);
if(i!=1){
query_minn(); //查询和该数匹配最小是多少
query_maxx(); //查询和该数匹配最大是多少
}
add(); //最后更新该数
}
printf("%lld %lld\n",minn,maxx);
return 0;
}
基本会使用字典树的话,这题就不算难,时间也够,1e6的数,每个数最坏查找10*18次,1e6*10*18=1.8*1e8
但时间是6000ms