1. 程式人生 > >一道題4

一道題4

splay mem scanf stdio.h 兩個 def color 元組 aps

$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