【BZOJ】4430: [Nwerc2015]Guessing Camels赌骆驼

【题意】给定三个长度为n的排列,求在三个排列中顺序相同的数对个数。

【算法】逆序对

【题解】很容易联想到NOIP火柴排队,涉及顺序问题显然和逆序对息息相关。

一个数对如果在三个排列中顺序不同,一定是1+2或2+1,也就是只在两数列之间顺序相同。

所以对三个数列两两求逆序对总数num,则不满足要求的数对一定会产生且仅产生两个逆序对,ans=n*(n-1)/2-num/2。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#define lowbit(x) x&-x
#define ll long long
using namespace std;
int read(){
    char c;int s=0,t=1;
    while(!isdigit(c=getchar()))if(c=='-')t=-1;
    do{s=s*10+c-'0';}while(isdigit(c=getchar()));
    return s*t;
}
const int maxn=200010;
ll ans;
int d[maxn],n,A[maxn];
struct cyc{int num,id;}a[maxn],b[maxn],c[maxn];
bool cmp(cyc a,cyc b){return a.num<b.num;}
void modify(int x){for(int i=x;i<=n;i+=lowbit(i))d[i]++;}
int query(int x){int ans=0;for(int i=x;i>=1;i-=lowbit(i))ans+=d[i];return ans;}
void calc(cyc a[],cyc b[]){
    memset(d,0,sizeof(d));
    for(int i=1;i<=n;i++)A[a[i].id]=b[i].id;
    for(int i=1;i<=n;i++){
        modify(A[i]);
        ans+=i-query(A[i]);
    }
}
int main(){
    n=read();
    for(int i=1;i<=n;i++)a[i].num=read(),a[i].id=i;
    for(int i=1;i<=n;i++)b[i].num=read(),b[i].id=i;
    for(int i=1;i<=n;i++)c[i].num=read(),c[i].id=i;
    sort(a+1,a+n+1,cmp);sort(b+1,b+n+1,cmp);sort(c+1,c+n+1,cmp);
    ans=0;
    calc(a,b);calc(b,c);calc(a,c);
    printf("%lld",1ll*n*(n-1)/2-ans/2);
    return 0;
}
View Code

 

posted @ 2017-11-04 07:42  ONION_CYC  阅读(221)  评论(0编辑  收藏  举报