【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; }