BZOJ 4430 赌骆驼
来源:互联网 发布:网络代理可信吗 编辑:程序博客网 时间:2024/05/18 01:25
先说这个玄学的思想
取补集,本来数对共有
思考不满足的对数:若不满足,则必有一次比较中两个数在两个排列中出现的顺序是相反的。
在三次两两排列的比较中,一共有两次出现次序相反
例如给出三个排列:{3,1,2},{2,3,1},{3,2,1},数对(1,2)很明显不满足条件,在1,2序列的比较中,出现第一次次序相反,1,3比较重第二次次序相反,而2,3的比较则满足,所以对于每一个数对,若不满足条件,则必定出现两次次序相反。
下面考虑怎么求出两个排列的比较中次序相反的对数,这里就有一个很玄学的想法。
引自->http://blog.csdn.net/braketbn/article/details/51392650
考虑下面这种情况,对于数对(x, y)
第一个排列:_x_u_y___k
第二个排列:___y_____x
(u与y下标相同,k与x下标相同)
我们从后向前遍历第一个排列。在遍历到k的时候,查询一下在第一个排列里x位置之前的前缀和,然后再在第一个排列里x位置+1。
遍历到u时,查询一下第一个排列里y位置之前的前缀和(这样就统计到了x位置上的1),然后再在第一个排列里y位置+1。
等于说从后向前扫,维护一个从前向后的前缀。统计对于第二个序列从后向前的数对中(通过for实现)在第二个序列中从前向后的对数(通过树状数组实现)。
#include<iostream>#include<cstring>#include<cstdio>#include<cstdlib> #include<algorithm>using namespace std;const int maxn=2000005;int n;int c[maxn],s[3][maxn],pos[maxn];void addition(int pos){ for(int i=pos;i<=n;i+=i&-i) c[i]++;}int query(int pos){ int res=0; for(int i=pos;i;i-=i&-i) res+=c[i]; return res;}long long solve(int *a,int *b){ long long res=0; for(int i=1;i<=n;i++) pos[b[i]]=i,c[i]=0; for(int i=n;i>0;i--) res+=query(pos[a[i]]),addition(pos[a[i]]); return res;}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",s[0]+i); for(int i=1;i<=n;i++) scanf("%d",s[1]+i); for(int i=1;i<=n;i++) scanf("%d",s[2]+i); long long ans=(1LL*n*(n-1))>>1; long long minus=0; minus+=solve(s[0],s[1]); minus+=solve(s[0],s[2]); minus+=solve(s[1],s[2]); minus>>=1; printf("%lld",ans-minus); return 0;}
还有一个很好想的方法,考虑将每一头骆驼出现的三次位置标为(x,y,z),用CDQ搞搞三维偏序就好了。很裸的CDQ嘛。。。
#include<iostream>#include<cstdlib>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn=2000005;int n,c[maxn];long long ans;struct node{ int x,y,z; bool operator < (const node &tmp) const { if(x==tmp.x) { if(y==tmp.y)return z<tmp.z; return y<tmp.y; } return x<tmp.x; }}q[maxn],point[maxn];int read(){ int x=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar(); return x;}void addition(int x,int val){ for(int i=x;i<=n;i+=i&-i) c[i]+=val;}int query(int x){ int res=0; for(int i=x;i;i-=i&-i) res+=c[i]; return res;}void cdq(int l,int r){ if(l==r)return; int mid=l+r>>1; for(int i=l;i<=r;i++) { if(q[i].y<=mid)addition(q[i].z,1); else ans+=query(q[i].z); } for(int i=l;i<=r;i++) if(q[i].y<=mid)addition(q[i].z,-1); int pl=l-1,pr=mid; for(int i=l;i<=r;i++) { if(q[i].y<=mid)point[++pl]=q[i]; else point[++pr]=q[i]; } for(int i=l;i<=r;i++) q[i]=point[i]; cdq(l,mid),cdq(mid+1,r);}int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)q[read()].x=i; for(int i=1;i<=n;i++)q[read()].y=i; for(int i=1;i<=n;i++)q[read()].z=i; sort(q+1,q+n+1); cdq(1,n); printf("%lld",ans);}
阅读全文
0 0
- BZOJ 4430 赌骆驼
- [BZOJ 4430] [NWERC 2015] 赌骆驼
- bzoj 4430: [Nwerc2015]Guessing Camels赌骆驼 (CDQ分治)
- [BZOJ]4430: [Nwerc2015]Guessing Camels赌骆驼 树状数组(思路好题)
- 【NWERC2015】【BZOJ4430】Guessing Camels赌骆驼
- [BZOJ4430][Nwerc2015]Guessing Camels赌骆驼
- 【bzoj4430】[Nwerc2015]Guessing Camels赌骆驼
- bzoj4430 [Nwerc2015]Guessing Camels赌骆驼(CDQ分治)
- 骆驼SPACE
- 骆驼感言
- 骆驼命名
- 小骆驼
- 【BZOJ4430】[Nwerc2015]Guessing Camels赌骆驼【树状数组】【或CDQ分治】
- [BZOJ4430][Nwerc2015]Guessing Camels赌骆驼(cdq分治+bit||bit)
- 象骆驼那样生活
- 动物园的骆驼
- 骆驼之国
- 骆驼奶的冰淇淋
- 优先队列的实现
- 【Linux】虚拟机vmware的安装
- Leetcode-Add Binary
- Asp.Net开发中未整理的资料
- python求数独全解
- BZOJ 4430 赌骆驼
- 几个常用创建型设计模式总结
- [Android Memory] 手动回收ImageVIew的图片资源
- MyBatis
- JAVA工程师面试题
- SQL学习—SELECT语句
- LinuxStudyNote(45)-管道符 | 的使用与解析、| 与 grep的使用
- HSL and HSV
- 前端之路——第一篇:认识前端简单的基础知识