BZOJ-4769: 超级贞鱼

[文章目录]

Description

马达加斯加贞鱼是一种神奇的双脚贞鱼,它们把自己的智慧写在脚上——每只贞鱼的左脚和右脚上各有一个数。有一天,K只贞鱼兴致来潮,排成一列,从左到右第i只贞鱼会在右脚写Ai,左脚上写上i;第二年,这K只贞鱼以右脚的数为第一关键字、左脚的数为第二关键字,从小到大排成一列。然后,它们决定重编号,从左到右第i只贞鱼会在右脚上写上左脚的数,在左脚上写i;第三年,它们按第二年的方法重排列、重编号......N年后,对于从左到右第i和第j贞鱼,若i<j且第i只贞鱼右脚上的数比第j只贞鱼右脚上的数大,则称它们为一对“超级贞鱼”。问一共有多少对“超级贞鱼”?K≤2×10^6, Ai≤10^9,N≤10^18

就是求在一个变幻规则下的逆序对个数。
发现,如果两个鱼是超级的,那么变幻之后,仍然为超级的。。。(弗兰奇!!!咳咳。。。)那么直接求一个逆序对数就好了。树状数组亲测卡常。还是用归并比较好

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int n,w[2001000],b[2001000];
inline void read(int &x)
{
    char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
}
long long ans;
void solve(int l,int r)
{
    if(l==r) return ;
    int mid=l+r>>1; solve(l,mid); solve(mid+1,r);
    int h1=l,h2=mid+1;
    for(int i=l;i<=r;++i)
    {
        if(h2>r||(h1<=mid&&w[h1]>w[h2])) ans+=r-h2+1,b[i]=w[h1++];
        else b[i]=w[h2++];
    }
    for(int i=l;i<=r;++i) w[i]=b[i];
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i) read(w[i]);
    solve(1,n); printf("%lld",ans);
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注