题目链接 : 点此传送
题意 :
T组测试样例,给你n个 用 val[i]%n(相同则后移) 哈希过的数组,让你还原成字典序最小的原数组
思路
建个优先队列每次都取最小的看能不能放,首先把所有直接能放入的点全部入队(就是 v[i]%n==i的),然后依次挑最小的往后填下一个数字,主要判断在i放入后 i+1 是否也能放入,看了大佬博客有两种简单方法,感觉比给的题解简单,他们都是判断v[i]%n 到 i所在位置之间是否全部填上,因为他是哈希是相同后移一位,后面那个填上的时候v[i]%n 到 i-1 肯定已经全部填上
1. 每次寻找他后面最近没有放入的点r,和前面最近没有放入的点 l, r与l之间的距离肯定会大于等于 r到 v[r]%n之间的距离,否则中间有空缺
2. 用并查集维护判断是否连续,每次加入一个点,都把他和他的下一位相连接,如果 v[i]%n到 i 之间有没填的,那么这条链就是从中间断开的,这时候 find(v[i]%n)!=i,也就不满足
代码(方法一)
#include<bits/stdc++.h>
using namespace std;
const long long maxn=2e5+7;
int v[maxn];
int vis[maxn];
int use[maxn];
int pal[maxn];
int nex[maxn];
int pre[maxn];
int main(){
int t;
scanf("%d",&t);
while(t--){
long long n;
scanf("%lld",&n);
for(int i=0;i<n;i++){
scanf("%d",&v[i]);
}
memset(vis,0,sizeof(vis));
memset(use,0,sizeof(use));
int cnt=0;
priority_queue<pair<int,int>,vector<pair<int,int>> ,greater<pair<int,int> > >q;
for(int i=0;i<n;i++){
if(v[i]%n==i&&v[i]!=-1) {
q.push(make_pair(v[i],i));
use[i]=1;
}
if(v[i]!=-1) cnt++;
}
int ans=0;
while(!q.empty()){
pair<int,int> p=q.top();
q.pop();
int cs=p.second;
vis[cs]=1;
pal[ans++]=p.first;
if(ans==cnt) break;
int l=(cs-1+n)%n;
int r=(cs+1)%n;
while(vis[l]) l=pre[l];
while (vis[r]) r=nex[r];
nex[cs]=r;
pre[cs]=l;
if(v[r]!=-1&&!use[r]&&((r-l-1+n+n)%n>=(r-v[r]%n+n)%n)){
q.push(make_pair(v[r],r));
use[r]=1;
}
}
if(ans!=cnt){
printf("-1\n");
}else{
if(ans==0) puts("");
else
for(int i=0;i<ans;i++){
printf("%d%c",pal[i],i==ans-1?'\n':' ');
}
}
}
return 0;
}
代码(方法二)
#include<bits/stdc++.h>
using namespace std;
const long long maxn=2e5+7;
int ss[maxn];
int v[maxn];
int pal[maxn];
int vis[maxn];
int find(int x){return x==ss[x]?x:ss[x]=find(ss[x]);}
void init(int n){for (int i=0;i<=n;i++)ss[i]=i,vis[i]=0;}
int main(){
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
init(n);
for(int i=0;i<n;i++){
scanf("%d",&v[i]);
}
priority_queue<pair<int,int>,vector<pair<int,int>> ,greater<pair<int,int>> >q;
int cnt=0,ans=0;
for(int i=0;i<n;i++){
if(v[i]!=-1&&v[i]%n==i) q.push(make_pair(v[i],i)),vis[i]=1;
if(v[i]!=-1) cnt++;
}
while(!q.empty()){
pair<int,int> p=q.top();
q.pop();
int cs=p.second;
pal[ans++]=v[cs];
if(ans==cnt) break;
int nex=(cs+1)%n;
ss[cs]=ss[nex];
int k=find(cs);
if(vis[k]|v[k]==-1) continue;
if(find(v[k]%n)==k){
q.push(make_pair(v[k],k));
vis[k]=1;
}
}
if(ans!=cnt){
printf("-1\n");
}else{
if(ans==0) puts("");
else
for(int i=0;i<ans;i++){
printf("%d%c",pal[i],i==ans-1?'\n':' ');
}
}
}
return 0;
}