暑假-树状数组-C - Ping pong

来源:互联网 发布:唐山炭知天下 编辑:程序博客网 时间:2024/05/22 01:51
/*题意:有N个乒乓球员,每个人都有一个技能值和屋子的位置(按顺序从1-N),现在要组织      一些比赛,比赛为2个球员要在他们的位置之间找一个裁判,并且裁判的技能值在他们  的技能值之间,问最多能组织多少场比赛(2个选手和1个裁判只要有一个不同都算一场)思路:以每个人作为裁判为参照物,那么他当裁判能组织的比赛就是(在他的位置之前技能值比      他小的) 乘以 (在他的位置之后技能比他大的)  和(加)  (在他的位置之前技能值比他大的)  乘以 (在他的位置之后技能值比他小的),相当于转换为求逆序数和顺序数的问题,可用树状数组*/#include<iostream>#include<cstring>using namespace std;const int MAXN=100001;//技能值上限const int MAXM=20005;//人员上限int c[MAXN],t,n;//树状数组int Fmin[MAXM],Fmax[MAXM],skill[MAXM];//Front-min:在他位置之前技能值比他小的,Front-max:在他的位置之前技能值比他大的//skill:每个人的技能值int lowbit(int x)//树状数组函数之一{return x&(-x);}int sum(int i)//树状数组函数之一{int s=0;while(i>0){s+=c[i];i-=lowbit(i);}return s;}void add(int i,int val)//树状数组函数之一{while(i<MAXN){c[i]+=val;i+=lowbit(i);}}int main(){cin>>t;while(t--){cin>>n;memset(c,0,sizeof(c));memset(Fmax,0,sizeof(Fmax));memset(Fmin,0,sizeof(Fmin));memset(skill,0,sizeof(skill));for(int i=1;i<=n;i++)//求位于他前面的(顺序){cin>>skill[i];Fmin[i]=sum(skill[i]);Fmax[i]=sum((MAXN-1))-Fmin[i];add(skill[i],1);//技能值对应的位置+1,表示他出现过了}memset(c,0,sizeof(c));long long int ans=0;//比赛总数for(int i=n;i>=1;i--)//求位于他后面的(逆序){int Bmin,Bmax;//Back-min:后面技能值比他小的,Back-max:后面技能值比他大的。Bmin=sum(skill[i]);Bmax=sum((MAXN-1))-Bmin;add(skill[i],1);ans+=((Fmin[i]*Bmax)+(Fmax[i]*Bmin));//2种情况相乘等于第i个人为裁判最多能组织的比赛场数}cout<<ans<<endl;}return 0;}


一开始没想到用树状数组求,直接用结构体模拟,然而数据比较大TLE了。

#include<iostream>#include<algorithm>using namespace std;const int MAXM=20005;struct Node{int val;int pos;};int t,n;Node skill[MAXM];bool cmp(Node a,Node b){return a.val<b.val;}int main(){cin>>t;while(t--){cin>>n;for(int i=1;i<=n;i++){cin>>skill[i].val;skill[i].pos=i;}sort(skill+1,skill+n+1,cmp);long long int ans=0;for(int i=1;i<=n;i++){int Fmin=0,Fmax=0,Bmin=0,Bmax=0;for(int j=1;j<i;j++){if(skill[j].pos<skill[i].pos){Fmin++;}else{Bmin++;}}for(int j=i+1;j<=n;j++){if(skill[j].pos<skill[i].pos){Fmax++;}else{Bmax++;}}ans+=(Fmin*Bmax+Fmax*Bmin);}cout<<ans<<endl;}return 0;}


0 0
原创粉丝点击