uoj386 【UNR #3】鸽子固定器
(似乎很久没写题解了)
题意:
n个物品,每个物品有a,b两个值,给定A,B,现在最多选其中m个,要求最大化选出的物品中【b权值和的B次方-a极差的A次方】。
$n\leq 2\times 10^5,m\leq 50.$
花絮:
大概全场最早ac的两人是miaom&wzf2000,用了非标算的“神奇的做法”,太强辣。
题解:
按照a排序以后转化为选定一个区间以后最大化区间内部的b权值和。
然后考虑两种情况:
- 如果区间长度小于等于m,那么一定是选择连续一段。
- 否则,区间内部剩余没有选择的物品,它们的b权值一定比选择的都小,否则可以替换获得更优解。
第一种情况暴力,第二种用链表维护,从小到大删去数,那么每次选择的同样是连续一段。
时间复杂度$\mathcal{O}(nm)$。
code:
1 #include<bits/stdc++.h> 2 #define rep(i,x,y) for (int i=(x);i<=(y);i++) 3 #define ll long long 4 #define inf 1000000001 5 #define y1 y1___ 6 using namespace std; 7 ll read(){ 8 char ch=getchar();ll x=0;int op=1; 9 for (;!isdigit(ch);ch=getchar()) if (ch=='-') op=-1; 10 for (;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0'; 11 return x*op; 12 } 13 #define N 300005 14 int n,m,A,B,id[N],l[N],r[N];ll ans,a1[N],a2[N],b1[N],b2[N]; 15 struct node{ 16 int a,b; 17 node(){} 18 node(int a_,int b_){a=a_,b=b_;} 19 }q[N]; 20 bool cmp(node x,node y){return x.a<y.a;} 21 bool cmp2(int x,int y){return q[x].b<q[y].b||q[x].b==q[y].b&&x<y;} 22 void upd(ll x,ll y){ 23 if (B==2) x=x*x;if (A==2) y=y*y; 24 ans=max(ans,x-y); 25 } 26 int main(){ 27 // freopen("A.in","r",stdin); 28 // freopen("A.out","w",stdout); 29 n=read(),m=read(),A=read(),B=read(); 30 rep (i,1,n) q[i].a=read(),q[i].b=read(),id[i]=i,l[i]=i-1,r[i]=i+1; 31 q[0]=node(0,0);q[n+1]=node(inf,0); 32 r[0]=1,l[n+1]=n,l[0]=0,r[n+1]=n+1; 33 sort(&q[1],&q[n+1],cmp); 34 sort(&id[1],&id[n+1],cmp2); 35 rep (i,1,n){//区间长度小于等于m 36 ll sum=0; 37 for (int j=i;j<=n&&j<=i+m-1;j++){ 38 sum+=q[j].b; 39 upd(sum,q[j].a-q[i].a); 40 } 41 } 42 rep (i,1,n){//区间长度大于m,从小到大删数 43 int x=id[i]; 44 b1[0]=q[x].b,b2[0]=0;a1[0]=a2[0]=q[x].a; 45 for (int j=1,l_=l[x],r_=r[x];j<=m;j++){ 46 b1[j]=b1[j-1]+q[l_].b,b2[j]=b2[j-1]+q[r_].b; 47 a1[j]=q[l_].a,a2[j]=q[r_].a; 48 l_=l[l_],r_=r[r_]; 49 } 50 rep (j,0,m-1) upd(b1[j]+b2[m-j-1],a2[m-j-1]-a1[j]); 51 r[l[x]]=r[x],l[r[x]]=l[x]; 52 } 53 cout<<ans<<'\n'; 54 return 0; 55 }