NOIP2013火柴排队

Solution

恕我直言,这题是真的坑。

对于这道题,一个很显然的思路是对于A B两个序列,他们交换完后相对的两个数在原序列中的相对大小是相同的,于是我们就把序列按照A排序,在把B离散化,求逆序对,诶,这题真水。

期望得分100,实际得分10。

WTF???我写挂了??

正解,将A,B分别排序,c[a[i].pos]=b[i].pos,再将c求一波逆序对。

为什么这样可以,而上一种做法不行?

随便举个栗子

2 4 5 6 1 3

3 4 1 6 5 2

这是离散化后的序列,我们固定A序列,让B序列动,那么对于B序列来说,3应当在第六个,4应当在2个,1应当在第五个,6应当在第四个,5应当在第三个,2应当在第一个。于是B序列就变成了

6 2 5 4 3 1

这就是正解的合理性,而错误解法通过直接排序,将相邻元素的相对顺序打乱了,导致求出的解一定是错的(但是样例都能过【喷血】)。

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#define mod 99999997 
#define N 100009
using namespace std;
long long n,tot,tr[N],c[N];
long long ans;
struct de
{
long long a,b;
}a[N],b[N]; 
void add(int u)
{
while(u<=n)
{
tr[u]++;
tr[u]%=mod;
u+=u&-u;
}
}
long long q(int u)
{
long long an=0;
while(u)
{
an+=tr[u];
u-=u&-u;
}
return an;
}
bool cmp(de a,de b)
{
return a.a<b.a;
}
int main()
{
scanf("%lld",&n);
for(int i=1;i<=n;++i)
scanf("%lld",&a[i].a),a[i].b=i;
for(int i=1;i<=n;++i)
scanf("%lld",&b[i].a),b[i].b=i;
sort(a+1,a+n+1,cmp);
sort(b+1,b+n+1,cmp);
for(int i=1;i<=n;++i)
c[a[i].b]=b[i].b;
for(int i=1;i<=n;++i) 
{
(ans+=i-q(c[i])-1)%=mod;
add(c[i]);
}
// for(int i=1;i<=n;++i)
// cout<<c[i]<<" ";
cout<<ans;
return 0;
}



最后一句话

Think twice,code once

原文地址:https://www.cnblogs.com/ZH-comld/p/9389192.html