http://acm.split.hdu.edu.cn/showproblem.php?pid=5792
题意:
思路:
lmin[i]:表示左边比第i个数小的个数。
lmax[i]:表示左边比第i个数大的个数。
rmin[i]:表示右边比第i个数小的个数。
rmax[i]:表示右边比第i个数大的个数。
这些都是可以用树状数组计算出来的,把所有的lmin加起来就是所有(a,b)对的个数,所有lmax加起来就是所有(c,d)对的个数,两者相乘就是所有情况之和了。但是需要注意的是,在这些情况中还存在a=c,a=d,b=c,b=d这四种不符合题意的,需要把这些给减掉。
1 #include<iostream> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdio> 5 #include<vector> 6 #include<stack> 7 #include<queue> 8 #include<cmath> 9 #include<map> 10 #include<set> 11 using namespace std; 12 typedef long long ll; 13 typedef pair<int,int> pll; 14 const int INF = 0x3f3f3f3f; 15 const int maxn = 50000+5; 16 17 int n; 18 int a[maxn],b[maxn],c[maxn]; 19 int lmin[maxn],lmax[maxn],rmin[maxn],rmax[maxn]; 20 21 int lowbit(int x) 22 { 23 return x&-x; 24 } 25 26 int get_sum(int x) 27 { 28 int ret = 0; 29 while(x>0) 30 { 31 ret+=c[x]; 32 x-=lowbit(x); 33 } 34 return ret; 35 } 36 37 void add(int x) 38 { 39 while(x<=n) 40 { 41 c[x]+=1; 42 x+=lowbit(x); 43 } 44 } 45 46 int main() 47 { 48 //freopen("in.txt","r",stdin); 49 while(~scanf("%d",&n)) 50 { 51 for(int i=1;i<=n;i++) 52 { 53 scanf("%d",&a[i]); 54 b[i]=a[i]; 55 } 56 sort(b+1,b+n+1); 57 int num=unique(b+1,b+n+1)-(b+1); 58 for(int i=1;i<=n;i++) 59 a[i]=lower_bound(b+1,b+num+1,a[i])-(b+1)+1; 60 61 ll suml=0,sumr=0; 62 memset(c,0,sizeof(c)); 63 for(int i=1;i<=n;i++) 64 { 65 lmin[i]=get_sum(a[i]-1); 66 lmax[i]=get_sum(n)-get_sum(a[i]); 67 add(a[i]); 68 suml+=lmin[i]; 69 sumr+=lmax[i]; 70 } 71 memset(c,0,sizeof(c)); 72 for(int i=n;i>=1;i--) 73 { 74 rmin[i]=get_sum(a[i]-1); 75 rmax[i]=get_sum(n)-get_sum(a[i]); 76 add(a[i]); 77 } 78 79 ll ans=suml*sumr; 80 81 for(int i=1;i<=n;i++) 82 { 83 ans-=(ll)rmin[i]*rmax[i];//a==c==a[i] 84 ans-=(ll)lmin[i]*lmax[i];//b==d==a[i] 85 ans-=(ll)lmin[i]*rmin[i];//b==c==a[i] 86 ans-=(ll)lmax[i]*rmax[i];//a==d==a[i] 87 } 88 printf("%lld ",ans); 89 } 90 return 0; 91 }