[BalticOI 2022] Uplifting Excursion (Day1) 题解

我们考虑先将选的数之和 \(sum\) 转化到一定范围内,再进行背包 \(dp\),这样就可以减少时间空间复杂度了。

其他的都是简单多重背包,时间复杂度 \(O(m^3\log^2m)\),假如用单调队列写应该就是 \(O(m^3)\) 了。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=305;
int n,m,dl,ad,sum,sz;
int a[N*2],b[N*2],f[N*N*2];
void add(int w,int v,int c){
	for(int s=1;c>0;c-=s,s*=2){
		int k=min(s,c);ad=k*w,dl=k*v;
		if(w>0) for(int i=sz;i>=ad;i--)
			f[i]=max(f[i],f[i-ad]+dl);
		else for(int i=0;i<=ad+sz;i++)
			f[i]=max(f[i],f[i-ad]+dl);
	} 
}signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m,sz=n*n*2;
	for(int i=0;i<=2*n;i++){
		cin>>a[i],b[i]=a[i],dl+=(i<n)*a[i]*(i-n);
		ad+=(i>n)*a[i]*(i-n),sum+=a[i]*(i-n);
	}if(m<dl||m>ad) return cout<<"impossible",0;
	if(sum>m) for(int i=2*n;i>n;i--)
		sum-=(i-n)*(a[i]-(b[i]-=min(a[i],(sum-m)/(i-n))));
	else for(int i=0;i<n;i++)
		sum-=(i-n)*(a[i]-(b[i]-=min(a[i],(m-sum)/(n-i))));
	for(int i=0;i<=sz;i++) f[i]=-1e18;f[n*n-m+sum]=0;
	for(int i=0;i<=2*n;i++) f[n*n-m+sum]+=b[i];
	for(int i=0;i<=2*n;i++){
		if(i==n) continue;
		if(b[i]) add(n-i,-1,min(b[i],sz));
		if(a[i]-b[i]) add(i-n,1,min(a[i]-b[i],sz));
	}(f[n*n]<0)?cout<<"impossible":cout<<f[n*n];
	return 0;
} 
posted @ 2025-02-21 12:02  长安一片月_22  阅读(14)  评论(0)    收藏  举报