[NOIP2013]火柴排队(逆序对)

题目

思路

逆序对只会猜结论

显然需要先猜个结论:\(a\)数列第\(i\)大对应\(b\)数列第\(i\)大时平方和有最小值

通过交换法,需证明:\((b_i-a_j)^2+(b_j-a_i)^2 > (b_i-a_i)^2+(b_j-a_j),(j<i)\)

上式化简得:\(a_j<a_i\),显然成立

\(pa_i\)表示\(i\)这个数在\(a\)数列的哪个位置,\(pb_i\)同理

设数列\(b_{pa_i}=pb_i\),由于需要位置对齐,需要\(b_{pa_i}=pa_i\),即\(b_i=i\)

问题变成求b序列经过多少次交换变成有序序列

显然逆序对

Code

#include<bits/stdc++.h>
#define N 200005
#define lowbit(x) ((x)&(-(x)))
#define Min(x,y) ((x)<(y)?(x):(y))
#define Max(x,y) ((x)>(y)?(x):(y))
using namespace std;
typedef long long ll;
const ll mod = 99999997; 
int n,b[N],c[N];
struct Node
{
    int a,loc;
}A[N],B[N];

template <class T>
void read(T &x)
{
    char c; int sign=1;
    while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
}
bool cmp(Node a,Node b) { return a.a<b.a; }
void update(int x,int v) { for(;x<N;x+=lowbit(x)) c[x]+=v; }
int query(int x) { int ret=0; for(;x;x-=lowbit(x)) ret+=c[x]; return ret; } 
int main()
{
    read(n);
    for(int i=1;i<=n;++i) read(A[i].a),A[i].loc=i;
    for(int i=1;i<=n;++i) read(B[i].a),B[i].loc=i;
    sort(A+1,A+n+1,cmp);
    sort(B+1,B+n+1,cmp);
    for(int i=1;i<=n;++i) b[A[i].loc]=B[i].loc;
    ll ans=0;
    for(int i=n;i>=1;--i)
    {
        ans=(ans+query(b[i]-1))%mod;
        update(b[i],1);
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Chtholly/p/11779211.html