C
two-pointers裸题,每个人单独考虑,记得排序,然后每次一遍双指针,O(n^2)

#include<bits/stdc++.h> using namespace std; const int N=5005; struct node{int x,id;}a[N]; int n,b[N],ans1[N],ans2[N]; bool cmp(node a,node b){return a.x>b.x;} int main() { int T;scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1,x;i<=n;i++)scanf("%d",&x),a[i]=(node){x,i}; sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++)scanf("%d",&b[i]); for(int i=1;i<=n;i++) { int mx=a[i].x+b[1],mn=a[i].x+b[n],cnt1=0,cnt2=0,pos=2; for(int j=1;j<=n;j++) if(i!=j) { if(a[j].x+b[n]>mx)++pos,++cnt1; else{ int p=pos,ret=n-pos+1,num=0; for(int k=n;k>=j;k--) if(i!=k) { while(b[p]+a[k].x>mx)++p; if(p>n)break; ++num,++p; } cnt1+=ret-num; break; } } ans1[a[i].id]=cnt1+1; pos=n-1; for(int j=1;j<=n;j++) if(i!=j) { if(a[j].x>mn)--pos,++cnt2; else{ int p=pos; for(int k=j;k<=n;k++) if(i!=k) { if(p<1)break; while(b[p]+a[k].x<=mn)--p; if(p<1)break; ++cnt2,--p; } break; } } ans2[a[i].id]=cnt2+1; } for(int i=1;i<=n;i++)printf("%d %d ",ans1[i],ans2[i]); } }
G
树状数组签到题。
每次询问记录左右端点,然后用树状数组记录当前位置是否存在(存在为1不存在为0)。然后对于询问则采用二分位置+树状数组查询。
可能有同学会好奇为什么不能线段树,这样可以少个log……这很简单,内存是256MB,线段树要开4倍大小,会爆内存

#include<bits/stdc++.h> using namespace std; const int N=2e7+7; int n,l,r,now,num,c[N],a[N/2],p[N]; void add(int x,int v){while(x<=n)c[x]+=v,x+=x&-x;} int ask(int x){int ret=0;while(x)ret+=c[x],x-=x&-x;return ret;} int main() { int q,x;scanf("%d",&q); l=q+1,r=q,n=2*q; while(q--) { char c=getchar(); while(c<'A'||c>'Z')c=getchar(); if(c=='L') { ++num,p[--l]=++now,a[now]=l; add(l,1); } else if(c=='R') { ++num,p[++r]=++now,a[now]=r; add(r,1); } else if(c=='G')scanf("%d",&x),add(a[x],-1),--num; else{ int pos=num/2+1,L=l,R=r,mid,ans=r; while(L<=R) { mid=L+R>>1; if(ask(mid)-ask(l-1)>=pos)ans=mid,R=mid-1; else L=mid+1; } printf("%d ",p[ans]); } } }
未完待续……