很少遇到经典的题目,这个不算经典但是却也非常精彩。题目
题目大意:给定两个两个1-n的排列,定义两个排列的距离为:所有相同数字之间距离的最小值,More formally, it's such minimum |i - j|, that ai = bj.定义A cyclic shift number i (1 ≤ i ≤ n) of permutation b consisting from n elements is a permutation bibi + 1... bnb1b2... bi - 1. Overall a permutation has n cyclic shifts. 输出者n个cyclic shifts的距离。
eg:
4 2 1 3 4 3 4 2 1输出 2 1 0 1
解题思路:由于n很大(10^5),所以,我想到应该是O(nlogn)的算法,我想到线段树,但是怎么也想不出来怎么维护,后来和同学讨论,想到一种方法:第一个序列为A,第二个需要旋转的为B,即使维护B中的值是在A中对应值得左边还是右边,如果是左边,那么旋转之后距离+1,右边则-1,如果我们维护这两个优先队列,当-1的元素-到0时,则插入到左边的序列中,右边的序列删除。对于头上需要移动到最后的元素,则插入操作,和删除操作。说的可能有点乱!
但是有几个难点:1)删除操作怎么处理?优先队列,不管是用堆实现还是stl都没有删除的操作,我的方法是,每一个元素都有一个时间戳,如果出队的元素时间戳过时了,那么直接出对,不用管。这样就达到了删除的作用
2)对于整个优先队列的+1和-1操作,可以考虑使用延迟加减的操作,理解就是,既然整个都+1相当于没有+1,也就是出队的时候在+1就是了,这样的话,插入需要注意了,插入前要加减这个延迟,才能保证出队是的值的正确性。
code:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <stdlib.h>
using namespace std;
#define N 100010
int dat1[N],dat2[N];
int pos[N];
struct note
{
int val,time,index;
note(){}
note(int _v,int _t,int _i):val(_v),time(_t),index(_i){}
};
struct cmp
{
bool operator() ( note a, note b )
{
return a.val > b.val;
}
};
int _time[N];
int main()
{
int n;
while(cin >> n)
{
for(int i = 0;i < n;i++) scanf("%d",&dat1[i]);
for(int i = 0;i < n;i++) scanf("%d",&dat2[i]);
for(int i = 0;i < n;i++) pos[dat1[i]] = i;
priority_queue < note ,vector<note> ,cmp > l_queue,r_queue;
memset(_time,0,sizeof(_time));
for(int i = 0;i < n;i++)
{
//在原数的左侧
if(pos[ dat2[i] ] >= i) l_queue.push( note(pos[dat2[i]] - i,0, pos[ dat2[i] ] ) );
else r_queue.push( note(i-pos[dat2[i]],0, pos[ dat2[i] ] ) );
}
int t = 0;
int now_time = 1;
for(int i = 0;i < n;i++)
{
while(l_queue.empty() == 0 && l_queue.top().time != _time[l_queue.top().index]) l_queue.pop();
while(r_queue.empty() == 0 && r_queue.top().time != _time[r_queue.top().index]) r_queue.pop();
if(l_queue.size() == 0) cout << r_queue.top().val - t << "\n";
else if(r_queue.size() == 0) cout << l_queue.top().val + t << "\n";
else cout << min(l_queue.top().val+t,r_queue.top().val-t) << "\n";
if(i == n-1) continue;
t++;
int ttt = dat2[i];
r_queue.push(note(n-1 - pos[ttt] + t,now_time,pos[ttt] ));
_time[pos[ttt]] = now_time++;
while(r_queue.empty() == 0 && r_queue.top().val - t == 0)
{
note tt = r_queue.top();r_queue.pop();
tt.val = 0-t;
l_queue.push(tt);
}
}
}
return 0;
}
ps:我很喜欢这个题~