https://acm.hdu.edu.cn/showproblem.php?pid=7068
第 $i$ 个人初始得分为 $a_i$ ,每个人还可以不重复地取序列b中的一个数,最后按照分数从大到小排名。求每个人最好/最坏情况的排名。
撒,细数我的罪恶(
题目看错$n$次,还一直坚信二分能够极限卡过去。(
(u1s1看数据范围内说最多8组$n=5000$我还以为真能卡过去结果我就SB了)
最开始不难想到排名可以二分,检验的复杂度是$O(n)$的(贪心,为了维持排名我们需要至少一定数量的人比我们分高/低,显然初始得分越高/低的人越容易达成条件,而对于这些人,我们分配他们b中的大/小数,并且初始分越大的给的b越小即可。)
此时复杂度还过不去,但是跑几组数据发现如果我们从大到小对初始得分排序的话可以发现最好/最坏情况是单调不增的(想想也是,我真傻,真的,在这破地方卡了2h),因此最终复杂度为$O(n^2)$
#include<cmath> #include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int N=5005; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct men{ int w,i; }a[N]; int b[N]; bool cmp(men x, men y){ return x.w>y.w; } int l[N],r[N],n; bool check1(int x,int i){ if(x==1)return 1; int cnt=x-1; for(int j=1;j<=n;j++){ if(i!=j){ if(a[j].w+b[cnt--]<=a[i].w+b[n])return 0; if(cnt<1)break; } } return 1; } bool check2(int x,int i){ if(x==n)return 1; int cnt=x+1; for(int j=n;j>=1;j--){ if(i!=j){ if(a[j].w+b[cnt++]>a[i].w+b[1])return 0; if(cnt>n)break; } } return 1; } int main(){ int T=read(); while(T--){ n=read(); for(int i=1;i<=n;i++){ a[i].w=read();a[i].i=i; } for(int i=1;i<=n;i++){ b[i]=read(); } sort(a+1,a+n+1,cmp); int L=1,R=1; for(int i=1;i<=n;i++){ while(R!=n&&check1(R+1,i))R++; while(L!=n&&!check2(L,i))L++; l[a[i].i]=L,r[a[i].i]=R; } for(int i=1;i<=n;i++){ printf("%d %d ",l[i],r[i]); } } return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++