Luogu P1966 火柴排队

这还是一道比较简单的题目,稍微想一下就可以解决。终于有NOIP难度的题目了

首先我们看那个∑(ai-bi)^2的式子,发现这个的最小值就是排序不等式

所以我们只需要改变第一组火柴的顺序,使它和第二组火柴相对应(即大的对大的,小的对小的

然后我们离散一下,找出每一个数该去的位置

然后注意到这里的交换方式,相邻交换,这就直接转化为求逆序对的问题了

然后直接上树状数组即可

CODE

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=100005,mod=99999997;
struct data
{
    int x,num;
}a[N],b[N];
int tree[N],r[N],n,ans;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch=tc();
    while (ch<'0'||ch>'9') ch=tc();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc();
}
inline bool comp(data a,data b)
{
    return a.x<b.x;
}
inline void inc(int &x,int y)
{
    if ((x+=y)>=mod) x-=mod;
}
inline int lowbit(int x)
{
    return x&(-x);
}
inline int get(int x)
{
    int tot=0;
    while (x) inc(tot,tree[x]),x-=lowbit(x);
    return tot;
}
inline void add(int x)
{
    while (x<=n) inc(tree[x],1),x+=lowbit(x);
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i;
    for (read(n),i=1;i<=n;++i)
    read(a[i].x),a[i].num=i;
    for (i=1;i<=n;++i)
    read(b[i].x),b[i].num=i;
    sort(a+1,a+n+1,comp);
    sort(b+1,b+n+1,comp);
    for (i=1;i<=n;++i)
    r[a[i].num]=b[i].num;
    for (i=1;i<=n;++i)
    {
        inc(ans,get(n)-get(r[i]));
        add(r[i]);
    }
    printf("%d",ans);
    return 0;
}
posted @ 2018-05-21 13:27  空気力学の詩  阅读(152)  评论(0编辑  收藏  举报