Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 2302 | Accepted: 879 |
Description
Input
Output
Sample Input
1 3 1 2 3
Sample Output
1
讲解:一条大街上住着n个乒乓球爱好者,经常组织比赛,每个人都有一个不同的技能值ai,每场比赛需要三个人,一个裁判,两个队员,有个奇怪的规定,裁判必须住在两名选手中间,并且技能也在两者之间,
求以功能组织多少场比赛;
解:考虑每一个人当裁判的时候,前面大于他的,后面小于他的,前面小于他的,后面大于他的,相乘并相加,然后统计:
AC代码:
1 #include<iostream> 2 #include<algorithm> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 const int N = 20010; 7 const int M = 100010; 8 int x[M],y[M],ymin[M],ymax[M]; 9 int a[N],lef[N],right[N],leftm[N]; 10 int n; 11 int lowbit(int x) 12 { 13 return x&(-x); 14 } 15 void init( )//统计整体中小于等于i的数共有多少个,表示为ymin[i] 16 { 17 for(int i =1; i<=M; i++) 18 { 19 ymin[i] = ymin[i-1]+y[i];//n个数中共有多少个小于等于i,以后要减去1; 20 ymax[i] = n - ymin[i];//n个数中有多少大于i的; 21 } 22 } 23 void add(int i,int c)//插入一个数,计算一下后面的 24 { 25 while(i<=M)//第一次提交写了个N,于是wa啦 26 { 27 x[i] = x[i]+c; 28 i=i+lowbit(i); 29 } 30 } 31 int solve(int c) 32 { 33 int sum = 0; 34 while(c>0) 35 { 36 sum = sum+x[c]; 37 c = c-lowbit(c); 38 } 39 return sum; 40 } 41 int main() 42 { 43 int T; 44 long long ans; 45 scanf("%d",&T); 46 while(T--) 47 { 48 ans = 0; 49 memset(x,0,sizeof(x)); 50 memset(y,0,sizeof(y)); 51 scanf("%d",&n); 52 for(int i =1; i<=n; i++) 53 { 54 scanf("%d",&a[i]); 55 y[a[i]] = 1; 56 } 57 init( ); 58 for(int i = 1;i<=n;i++) 59 { 60 add(a[i],1); 61 lef[i] = solve(a[i]-1);//求前面小于a[i]的数; 62 leftm[i] = i-1-lef[i];//求前面大于a[i] 的数; 63 int ma = ymax[a[i]] - leftm[i];//后面大于a[i]的数; 64 int mb = ymin[a[i]] -1 - lef[i];//后面小于a[i]的数; 65 ans = ans + lef[i]*ma +leftm[i]*mb;//前大后小,前小后大; 66 } 67 printf("%lld\n",ans); 68 } 69 return 0; 70 }
poj Ping pong LA 4329 (树状数组统计数目)
原文:http://www.cnblogs.com/lovychen/p/4445029.html