【BOI2022】Uplifting Excursion

【BOI2022】Uplifting Excursion

by AmanoKumiko

Description

\(2m+1\)种物品,重量从\(-m\)\(m\),第\(i\)种有\(a_i\)

求组成重量为\(L\)时,最多能选多少个物品

Input

第一行两个数\(m,L\)

然后一行\(2m+1\)个数读入\(a\)

Output

一行一个数表示答案

若无解,输出impossible

Sample Input

2 5
2 3 1 1 4

Sample Output

9

Data Constraint

\(1\le m\le 300,-10^{18}\le l\le 10^{18},0\le a_i\le 10^{12}\)

Solution

考虑我们先把所有的数选上,最后再对其调整

那么我们首先贪心出一组解

这样我们的总重量就落在了\((L-m,L+m)\)

然后对其调整,每次加入或删除一个数

通过观察题解,可以发现调整的次数是不超过\(2m+1\)

大概就是说可以通过对调整重新排列,使得每次的总重量落在\((L-m,L+m)\)

若相同则可以删去

于是我们现在就可以直接背包了

由于我懒所以写了二进制分组(

Code

#include<bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a;i<=b;i++)
#define Fd(i,a,b) for(int i=a;i>=b;i--)
#define S 200000
#define LL long long
#define N 610

int m;
LL L,w,d,a[N],b[N],c[N],ans,t;
LL f[2*S+10];

int main(){
	scanf("%d%lld",&m,&L);
	F(i,-m,m)scanf("%lld",&a[i+m]);
	F(i,-m,m)if(i!=0)w+=a[i+m]*i,t+=a[i+m],c[i+m]=a[i+m];
	d=w-L;
	if(d>0){
		Fd(i,m,1){
			LL x=min(a[i+m],(w-L)/i);
			t-=x;
			w-=x*i;
			c[i+m]=a[i+m]-x;
			if(x<a[i+m]){
				t--;
				w-=i;
				c[i+m]--;
				break;
			}
		}
		if(w>L){printf("impossible");return 0;}
	}else{
		F(i,-m,-1){
			LL x=min(a[i+m],(L-w)/(-i));
			t-=x;
			w+=x*(-i);
			c[i+m]=a[i+m]-x;
			if(x<a[i+m]){
				t--;
				w+=(-i);
				c[i+m]--;
				break;
			}
		}
		if(w<L){printf("impossible");return 0;}
	}
	memset(f,128,sizeof(f));
	LL inf=f[0];
	f[w-(L-S)]=t;
	F(i,-m,m)if(i!=0){
		int ins=min((LL)2*m+1,a[i+m]-c[i+m]),del=min((LL)2*m+1,c[i+m]);
		F(j,0,10){
			if(ins>=(1<<j)){
				ins-=(1<<j);
				if(i>0){Fd(k,2*S,(1<<j)*i)f[k]=max(f[k],f[k-(1<<j)*i]+(1<<j));}
				if(i<0){F(k,0,2*S+i*(1<<j))f[k]=max(f[k],f[k-(1<<j)*i]+(1<<j));}
			}
			if(del>=(1<<j)){
				del-=(1<<j);
				if(i>0){F(k,0,2*S-i*(1<<j))f[k]=max(f[k],f[k+(1<<j)*i]-(1<<j));}
				if(i<0){Fd(k,2*S,-i*(1<<j))f[k]=max(f[k],f[k+(1<<j)*i]-(1<<j));}
			}
		}
		if(ins){
			if(i>0){Fd(k,2*S,ins*i)f[k]=max(f[k],f[k-ins*i]+ins);}
			if(i<0){F(k,0,2*S+i*ins)f[k]=max(f[k],f[k-ins*i]+ins);}
		}
		if(del){
			if(i>0){F(k,0,2*S-i*del)f[k]=max(f[k],f[k+del*i]-del);}
			if(i<0){Fd(k,2*S,-i*del)f[k]=max(f[k],f[k+del*i]-del);}
		}
	}
	if(f[S]<0)printf("impossible");
	else printf("%lld",f[S]+a[m]);
	return 0;
}
posted @ 2022-08-02 22:05  冰雾  阅读(76)  评论(0编辑  收藏  举报