【题解】[ABC221G] Jumping sequence
很好奇怎么没有题解提到复杂度更优的做法。
题目大意
有一个无限大的平面直角坐标系,初始时你在
-
f_{l,r,w} \leftarrow f_{l+1,r,w} -
f_{l,r,w+a_r} \leftarrow f_{l,r-1,w}(w \leq C) -
f_{l,r,w-a_l} \leftarrow f_{l+1,r,w}(w > C)
但是时间复杂度相比普通背包并没有优化。考虑重新设计 dp,设
转移时还是考虑上一步从哪边转移,以及
从左边转移但不操作
状态数变少了,但复杂度没变,其瓶颈在于第
初值为
同理,这个做法还可以求背包最大体积。
代码
目前最优解 85ms。
#include<bits/stdc++.h>
using namespace std;
using namespace my_std;
ll n,A,B,lim=1800,d[2020],f[2020][4040],ans0[2020],ans[2020];
pair<ll,ll> lst[2020][4040];
il void upd(ll x,ll y,ll xx,ll yy,ll v){
if(f[x][y]<v){
f[x][y]=v;
lst[x][y]=MP(xx,yy);
}
}
il bl solve(ll C){
ll pos=0,sum=0;
fr(i,1,n){
if((sum+d[i])<=C){
sum+=d[i];
pos++;
}
else break;
}
if(pos==n&&sum<C) return 0;
fr(i,pos,n) fr(j,1,2*lim) f[i][j]=0;
f[pos][sum-C+lim]=pos+1;
fr(i,pos+1,n){
fr(j,1,2*lim) upd(i,j,i-1,j,f[i-1][j]);
fr(j,1,lim) upd(i,j+d[i],i-1,j,f[i-1][j]);
pfr(j,2*lim,lim+1) fr(k,f[i-1][j],f[i][j]-1) upd(i,j-d[k],i,j,k);
}
if(!f[n][lim]) return 0;
fr(i,1,pos) ans[i]=1;
fr(i,pos+1,n) ans[i]=0;
ll x=n,y=lim;
while(x>pos){
ll xx=lst[x][y].fir,yy=lst[x][y].sec;
if(xx==(x-1)&&yy==(y-d[x])) ans[x]=1;
else if(x==xx) ans[f[x][y]]=0;
x=xx;
y=yy;
}
return 1;
}
int main(){
n=read();
A=read();
B=read();
fr(i,1,n) d[i]=read();
A+=B;
B=A-2*B;
fr(i,1,n) A+=d[i];
fr(i,1,n) B+=d[i];
if(A<0||B<0||(A%2==1)||(B%2==1)){
pf("No");
return 0;
}
A/=2;
B/=2;
if(!solve(A)){
pf("No");
return 0;
}
fr(i,1,n) ans0[i]=ans[i];
if(!solve(B)){
pf("No");
return 0;
}
pf("Yes\n");
fr(i,1,n){
if(ans0[i]==ans[i]){
if(!ans0[i]) pc('L');
else pc('R');
}
else{
if(!ans0[i]) pc('D');
else pc('U');
}
}
}