大佬的难题
大意:
给你 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\n",(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\n",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 }