P1966 火柴排队

P1966 火柴排队

首先分析一下这个距离的式子\(\sum (a_i+b_i)^2=\sum a_i^2-2a_ib_i+b_i^2\)

从此我们能够看出,这个距离只与\(a_ib_i\)有关233

然后我们证明一下证明排列\(a_i~b_i\)最优

\(a<b,a,b \in A~c < d c,b \in B\)
\(ac+bd > ad+bc\)
\(a(c-d)+b(d-c) > 0\)

\(\therefore (a-b)(c-d) > 0\)

\(\because a<b,c<d\)

\((a-b)(c-d)\)成立

\(\because (a-b)(c-d) > 0\)

\(\therefore ac+bd > ad+bc\)
所以小的和小的排在一起,大的和大的排在一起最优

然后我们继续考虑这么排序,我们肯定不会蹦着排序,这样中间的拍好了,后面的姚拍到前面,就会白费工。

扫描二维码关注公众号,回复: 1807025 查看本文章

所以就是根据一组排序另一组。

然后我们考虑下标,两边同样的大的(相对的) 肯定在达到最优状态之后,他们的下标一定是相同的,然后根据我们上面的YY,也会是其中至少一个的原来的下标。

然后对于需要移动的组,我们需要保证达到最优的时候,和已经定序的数组同样大小的数字下标相同。

也就是升序,然后对于这种情况,就是求所有的逆序对的个数

然后我感觉写完,好意识流呀

#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
struct node
{
    int val;
    int pos;
};
node a[1000100],b[1000100];
int base_a[1000100],base_b[1000100];
const int mode=99999997;
int n;
bool compare(const node &a,const node &b)
{
    return a.val>b.val;
}
int bit[1000100];
void ins(int pos)
{
    while(pos<=n+1)
    {
        bit[pos]+=1;
        pos+=pos&(-pos);
    }
    return ;
}
int sum(int pos)
{
    int res=0;
    while(pos)
    {
        res=(res+bit[pos])%mode;
        pos-=pos&(-pos);
    }
    return res;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i].val),a[i].pos=i;
    for(int i=1;i<=n;i++)
        scanf("%d",&b[i].val),b[i].pos=i;
    sort(a+1,a+1+n,compare);
    sort(b+1,b+1+n,compare);
    for(int i=1;i<=n;i++)
        base_a[i]=a[i].pos;
    for(int i=1;i<=n;i++)
        base_b[b[i].pos]=base_a[i];
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        ans=(ans+sum(n-base_b[i]))%mode;
        ins(n-base_b[i]+1);
    }
    printf("%d",ans);
}

猜你喜欢

转载自www.cnblogs.com/Lance1ot/p/9248730.html