码迷,mamicode.com
首页 > 其他好文 > 详细

一道题4

时间:2018-03-31 11:01:46      阅读:176      评论:0      收藏:0      [点我收藏+]

标签:下标   三元组   stream   ons   最大   memset   图片   alt   isp   

$n \leq 100000$的三个排列,求三元组$(x,y,z)$数量。一个合法的$(x,y,z)$是指存在一个下标集合$S$,$(x,y,z)=(max_{i \in S}a_i,max_{j \in S}b_j,max_{k \in S}c_k)$。

是一个数点问题。观察到:$S$中有用的下标只有1~3个,可分类。

有用下标有一个:$n$个下标均可。

有用下标有两个:可以用总的二元组$\frac{n(n-1)}{2}$减去满足$a_i>a_j,b_i>b_j,c_i>c_j$的数量。三维数点。

有用下标有三个:还是容斥,把三元组中一个下标有用、两个下标有用的情况排除掉。

一个下标有用的三元组:设一个$i$有$x$个$j$满足$a_i>a_j,b_i>b_j,c_i>c_j$,那么他在这的贡献是$\frac{x(x-1)}{2}$。

两个下标有用的三元组:这样的三元组,会有一个下标在两个数组中最大,一个下标在第三个数组最大,另一个没用。因此枚举两个数组,统计有多少是“一个下标在两个数组中最大的三元组”,这样的话上面那个“一个下标有用的三元组”会算3次,两个下标有用的三元组会算1次,减一下即可。

技术分享图片
 1 #include<stdio.h>
 2 #include<algorithm>
 3 #include<string.h>
 4 #include<stdlib.h>
 5 //#include<queue>
 6 #include<iostream>
 7 using namespace std;
 8 
 9 int n;
10 #define maxn 200011
11 #define LL long long
12 struct Poi{int a,b,c,ans;}p[maxn];
13 bool cmpa(const Poi &a,const Poi &b) {return a.a<b.a;}
14 bool cmpb(const Poi &a,const Poi &b) {return a.b<b.b;}
15 
16 struct BIT
17 {
18     int a[maxn],n;
19     void clear(int m) {n=m; memset(a,0,sizeof(a));}
20     void add(int x,int v) {for (;x<=n;x+=x&-x) a[x]+=v;}
21     int query(int x) {int ans=0; for (;x;x-=x&-x) ans+=a[x]; return ans;}
22 }t;
23 
24 void solve(int L,int R)
25 {
26     if (L==R) return;
27     int mid=(L+R)>>1;
28     solve(L,mid); solve(mid+1,R);
29     int i=L,j=mid+1;
30     while (i<=mid && j<=R)
31     {
32         if (p[i].b<p[j].b) t.add(p[i].c,1),i++;
33         else p[j].ans+=t.query(p[j].c-1),j++;
34     }
35     while (j<=R) p[j].ans+=t.query(p[j].c-1),j++;
36     for (i--;i>=L;i--) t.add(p[i].c,-1);
37     sort(p+L,p+R+1,cmpb);
38 }
39 
40 void c3()
41 {
42     for (int i=1;i<=n;i++) p[i].ans=0;
43     sort(p+1,p+1+n,cmpa);
44     t.clear(n);
45     solve(1,n);
46 }
47 
48 void c2(int type)
49 {
50     for (int i=1;i<=n;i++) p[i].ans=0; t.clear(n);
51     if (type==1) sort(p+1,p+1+n,cmpb); else sort(p+1,p+1+n,cmpa);
52     if (type==0) for (int i=1;i<=n;i++) p[i].ans=t.query(p[i].b-1),t.add(p[i].b,1);
53     else for (int i=1;i<=n;i++) p[i].ans=t.query(p[i].c-1),t.add(p[i].c,1);
54 }
55 
56 int main()
57 {
58     scanf("%d",&n);
59     for (int i=1;i<=n;i++) scanf("%d",&p[i].a);
60     for (int i=1;i<=n;i++) scanf("%d",&p[i].b);
61     for (int i=1;i<=n;i++) scanf("%d",&p[i].c);
62     
63     c3();
64     LL ans=n+1ll*n*(n-1)/2+1ll*n*(n-1)*(n-2)/6;
65     for (int i=1;i<=n;i++) ans-=p[i].ans-1ll*p[i].ans*(p[i].ans-1);
66     c2(0); for (int i=1;i<=n;i++) ans-=1ll*p[i].ans*(p[i].ans-1)/2;
67     c2(1); for (int i=1;i<=n;i++) ans-=1ll*p[i].ans*(p[i].ans-1)/2;
68     c2(2); for (int i=1;i<=n;i++) ans-=1ll*p[i].ans*(p[i].ans-1)/2;
69     printf("%lld\n",ans);
70     return 0;
71 }
View Code

 

一道题4

标签:下标   三元组   stream   ons   最大   memset   图片   alt   isp   

原文地址:https://www.cnblogs.com/Blue233333/p/8667339.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!