[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;
}

浙公网安备 33010602011771号