大佬的难题

大意:

给你 3 个长度为 N 的排列 {a i }, {b i }, {c i }, 求

∑[a x < a y ][b x < b y ][c x < c y ], N ≤ 10 5

1≤x,y≤n

题解:

直接容斥,设Sx,y表示满足上述式子的数量 答案即为Sx,y==3

容易发现Sx,y只能取2,3

设Pa,b 为a,b两个数组满足[ax<ay] [bx<by]的数量

然后显然Pa,b+Pb,c+Pa,c=3*Sx,y==3 + Sx,y==2

2Sx,y=Pab+Pbc+Pac-N*(N-1)>>1

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 using namespace std;
 8 typedef long long ll;
 9 const int N=2e6;
10 int n;
11 int a[N],b[N],c[N];
12 long long seed;
13 long long Rand() {
14 return seed = ((seed*19260817) ^ 233333) & ((1<<24)-1);
15 }
16 void gen(int *a) {
17     for(int i = 1; i <= n; i++) a[i] = i;
18     for(int i = 1; i <= n; i++) swap(a[i], a[Rand()%i + 1]);
19 }
20 struct node{
21     int a,b;
22     bool operator<(const node &p)const{return a<p.a;}
23 }tmp[N];
24 int Tree[N*4];
25 void add(int sta){
26     for(int i=sta;i<=n;i+=(i&(-i)))Tree[i]++;
27 }
28 int getsum(int sta){
29     int sum=0;
30     for(int i=sta;i>=1;i-=(i&(-i)))sum+=Tree[i];
31     return sum;
32 }
33 ll solve(int *a,int *b){
34     ll ans=0;
35     for(int i=1;i<=n;i++)tmp[i]=(node){a[i],b[i]};
36     sort(tmp+1,tmp+n+1);
37     for(int i=1;i<=n;i++){
38         ans+=getsum(tmp[i].b);
39         add(tmp[i].b+1);
40     }
41     memset(Tree,0,sizeof(Tree));
42     return ans;
43 }
44 int main()
45 {
46     freopen("dalao.in","r",stdin);
47     freopen("dalao.out","w",stdout);
48     scanf("%d",&n);
49     scanf("%lld",&seed);gen(a);
50     scanf("%lld",&seed);gen(b);
51     scanf("%lld",&seed);gen(c);
52     ll t1=(ll)n*(n-1)>>1;
53     ll t2=solve(a,b)+solve(a,c)+solve(b,c);
54     printf("%lld
",(t2-t1)>>1);
55     return 0;
56 }

另外就是60的CDQ 很好想:

以a先排个序,然后就是b,c的二维选点,CDQ nlog2n玩过

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 using namespace std;
 8 typedef long long ll;
 9 const int N=500005;
10 ll seed,ans=0;int a[N],b[N],c[N],n;
11 ll Rand(){
12     return seed=((seed*19260817)^233333)&((1<<24)-1);
13 }
14 void gen(int *a) {
15     for(int i=1;i<=n;i++)a[i]=i;
16     for(int i=1;i<=n;i++)swap(a[i],a[Rand()%i+1]);
17 }
18 struct node{
19     int a,b,c;
20 }q[N];
21 bool comp(const node &p,const node &pp){return p.a<pp.a;}
22 int Tree[N<<1];
23 void add(int sta,int ad){
24     for(int i=sta;i<=n;i+=(i&(-i)))Tree[i]+=ad;
25 }
26 int getsum(int sta){
27     int sum=0;
28     for(int i=sta;i>=1;i-=(i&(-i)))sum+=Tree[i];
29     return sum;
30 }
31 bool check(node px,node qx){
32     if(px.b!=qx.b)return px.b<=qx.b;
33     return px.c<=qx.c;
34 }
35 node tmp[N];
36 void cdq(int l,int r){
37     if(l>=r)return ;
38     int mid=(l+r)>>1;
39     int xl=l,xr=mid+1,m=0;
40     cdq(l,mid),cdq(mid+1,r);
41     while(xl<=mid && xr<=r){
42         if(check(q[xl],q[xr])){
43             add(q[xl].c,1);
44             tmp[++m]=q[xl++];
45         }
46         else{
47             ans+=getsum(q[xr].c);
48             tmp[++m]=q[xr++];
49         }
50     }
51     while(xl<=mid){
52         add(q[xl].c,1);
53         tmp[++m]=q[xl++];
54     }
55     while(xr<=r){
56         ans+=getsum(q[xr].c);
57         tmp[++m]=q[xr++];
58     }
59     for(int i=1;i<=m;i++){
60         if(tmp[i].a<=mid)add(tmp[i].c,-1);
61         q[l+i-1]=tmp[i];
62     }
63 }
64 void luang()
65     {
66         for(int i=1;i<=n;i++){
67             q[i].a=a[i];q[i].b=b[i];q[i].c=c[i];
68         }
69         sort(q+1,q+n+1,comp);
70         cdq(1,n);
71         printf("%lld
",ans);
72     }
73 void work()
74 {
75     scanf("%d",&n);
76     scanf("%lld",&seed);gen(a);
77     scanf("%lld",&seed);gen(b);
78     scanf("%lld",&seed);gen(c);
79     if(n<=N)luang();
80 }
81 
82 int main()
83 {
84     freopen("dalao.in","r",stdin);
85     freopen("dalao.out","w",stdout);
86     work();
87     return 0;
88 }
原文地址:https://www.cnblogs.com/Yuzao/p/7142021.html