您的位置:首页 > Web前端

bzoj4989&&luogu3656 [USACO17FEB]Why Did the Cow Cross the Road I P

2018-03-30 23:51 316 查看
http://www.elijahqi.win/archives/649

Description

Why did the cow cross the road? We may never know the full reason, but it is certain that Farmer Joh

n’s cows do end up crossing the road quite frequently. In fact, they end up crossing the road so oft

en that they often bump into each-other when their paths cross, a situation Farmer John would like t

o remedy.Farmer John raises N breeds of cows (1≤N≤100,000), and each of his fields is dedicated to

grazing for one specific breed; for example, a field dedicated to breed 12 can only be used for cow

s of breed 12 and not of any other breed. A long road runs through his farm. There is a sequence of

NN fields on one side of the road (one for each breed), and a sequence of N fields on the other side

of the road (also one for each breed). When a cow crosses the road, she therefore crosses between t

he two fields designated for her specific breed.Had Farmer John planned more carefully, he would hav

e ordered the fields by breed the same way on both sides of the road, so the two fields for each bre

ed would be directly across the road from each-other. This would have allowed cows to cross the road

without any cows from different breeds bumping into one-another. Alas, the orderings on both sides

of the road might be different, so Farmer John observes that there might be pairs of breeds that cro

ss. A pair of different breeds (a,b) is “crossing” if any path across the road for breed aa must int

ersect any path across the road for breed bb.Farmer John would like to minimize the number of crossi

ng pairs of breeds. For logistical reasons, he figures he can move cows around on one side of the ro

ad so the fields on that side undergo a “cyclic shift”. That is, for some 0≤k< N, every cow re-locat

es to the field kk fields ahead of it, with the cows in the last kk fields moving so they now popula

te the first kk fields. For example, if the fields on one side of the road start out ordered by bree

d as 3, 7, 1, 2, 5, 4, 6 and undergo a cyclic shift by k=2, the new order will be 4, 6, 3, 7, 1, 2,

5. Please determine the minimum possible number of crossing pairs of breeds that can exist after an

appropriate cyclic shift of the fields on one side of the road.上下有两个位置分别对应的序列A、B,长度为n,

两序列为n的一个排列。当Ai == Bj时,上下会连一条边。

你可以选择序列A或者序列B进行旋转任意K步,

如 3 4 1 5 2 旋转两步为 5 2 3 4 1。

求旋转后最小的相交的线段的对数。

Input

The first line of input contains N.

The next N lines describe the order, by breed ID, of fields on one side of the road;

each breed ID is an integer in the range 1…N.

The last N lines describe the order, by breed ID, of the fields on the other side of the road.

Output

Please output the minimum number of crossing pairs of breeds after a cyclic shift of the

fields on one side of the road (either side can be shifted).

Sample Input

5

5

4

1

3

2

1

3

2

5

4

Sample Output

0

HINT

Source

Platinum

看到这道题,我们可以想到2013年提高组火柴排队那道题,这道题其实同理,利用离散化的原理,预处理一个数组然后我们求逆序对就可以 最后求转完逆序对个数最小就可以

题目说两个都可以转,我一开始认为转一个就可以了,后来ly的提醒下发现转一个无论如何也不能满足转第二个产生的情况

比如我们观察这样一个序列

5 3 2 4 1 我们强制对第一行进行编号,1 2 3 4 5

2 1 4 3 5 根据第一行的编号,我们可以生成第二行 3 5 4 2 1

这时候我们去转动第二行,发现只是顺序改变了 比如变成5 4 2 1 3

假如我们转动第一行 3 2 4 1 5 再重新编号 1 2 3 4 5

这时候对应第二行 2 4 3 1 5 我们对比这两个红色的发现他们按照大小重新交换了一遍,相当于每个都减了一 所以只旋转一个是不可以的

1、用树状数组求初始数列的逆序对

2、不停旋转这个序列, 加入5 4 2 1 3 中3换到前面,那么因为交换3而导致的改变就是减去3前面比3大的数加上前面比3小的数就是3交换到前面对答案贡献的改变量

首先若a,b线段交叉且A[a]< A[b],则B[a]>B[b],若我们给A序列强制从小到大的标号,转换B序列保证符合原题。则线段交叉的对数,就是B序列中逆序对的个数。我们可以用树状数组nlogn求出。然后考虑循环移位,现在只考虑对B序列做循环移位(A序列同理,反过来做即可。),实质上就是对转换后的B序列做循环移位,我们每次只把最后一位挪到最前面,挪n-1次即可得到所有循环移位后的结果。考虑把最后一位x挪到第一位,对逆序对个数的影响是什么。因为操作之后x在第一位,所以所有比x小的都在他后面,构成了新的x-1个逆序对。原来比x大的现在都不再和x构成逆序对,所以少了(n-x)个以前的逆序对。而其他的位置没有变化。因此操作过后逆序对数的变化为x-1-(n-x)。这样我们只需用树状数组求出第一次的逆序对个数,以后的逆序对个数都可以O(1)得到,我们记录最小值即可。

tips:转A和转B得到的序列是不同的,必须做两次。

#include<cstdio>
#define N 110000
inline int read(){
int x=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x;
}
int s
,map
,c
,a
,b
,n;
inline void add(int x){while (x<=n){s[x]++;x+=x&(-x);}}
inline int query(int x){
int sum=0;
while (x){
sum+=s[x];x-=x&(-x);
}
return sum;
}
inline long long min(long long x,long long y){return x<y?x:y;}
int main(){
freopen("3656.in","r",stdin);
n=read();
for (int i=1;i<=n;++i) a[i]=read();for (int i=1;i<=n;++i) b[i]=read();
for (int i=1;i<=n;++i) map[a[i]]=i;
for (int i=1;i<=n;++i) c[i]=map[b[i]];
long long ans=0;
for (int i=1;i<=n;++i)add(c[i]),ans+=(long long
4000
)(i)-(long long)query(c[i]);
long long tmp=ans;
for (int i=n;i;--i) {
tmp+=(long long)(c[i]-1);tmp-=(long long) (n-c[i]);
ans=min(ans,tmp);
}
for (int i=1;i<=n;++i)s[i]=0;
for (int i=1;i<=n;++i) map[b[i]]=i;
for (int i=1;i<=n;++i) c[i]=map[a[i]];
long long ans1=0;
for (int i=1;i<=n;++i)add(c[i]),ans1+=(long long)(i)-(long long)query(c[i]);
tmp=ans1;
for (int i=n;i;--i) {
tmp+=(long long)(c[i]-1);tmp-=(long long) (n-c[i]);
ans1=min(ans1,tmp);
}
printf("%lld",min(ans1,ans));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: