CF28D Don't fear, DravDe is kind
阿新 • • 發佈:2018-10-11
tps get getch 限制 所有 har 根據 ems \n 相等的放在一組,每一組裏,記\(f_k\)為前綴重量為\(k\)的最大價值,轉移從前往後枚舉\(i\),從\(f_{l_i}\)向\(f_{l_i+p_i}\)轉移,這一組的答案應為\(f_{l_i+p_i+r_i}\)
傳送門
題意:\(n\)個位置,每個位置有價值\(v_i\)和重量\(p_i\),要選出一些位置,如果要選位置\(i\),那麽前面選的重量之和要為\(l_i\),後面選的重量之和要為\(r_i\),求一個方案使得價值和最大
這個限制很舒服,可以設\(f_i\)為從前面開始選,選第\(i\)個的最大價值,轉移枚舉前面的\(j\),如果能從\(j\)轉移過來,根據條件,要求\(l_i=l_j+p_i\&\&r_i=r_j-p_i\),記個轉移前綴就可以輸出方案了
但是這樣還不優,我們可以發現對於一個\(i\),只有\(l_j+p_j+r_j=l_i+p_i+r_i\)的\(j\)能夠轉移過來,於是可以把所有\(l_i+p_i+r_i\)
代碼賊醜,輕\(\mathfrak{D}\)qwq
#include<bits/stdc++.h> #define il inline #define re register #define LL long long #define ull unsigned long long #define db double #define eps (1e-7) using namespace std; const int N=200000+10,M=3000000+10; il LL rd() { LL x=0,w=1;char ch=0; while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*w; } int f[M],hd[M],nt[N]; int n,a[N][4],ma; int st[N],an[N],tt=0,pre[N],g[M]; int main() { n=rd(); for(int i=1;i<=n;i++) { a[i][0]=rd(),a[i][1]=rd(),a[i][2]=rd(),a[i][3]=rd(); int pp=a[i][1]+a[i][2]+a[i][3]; ma=max(ma,pp); nt[i]=hd[pp],hd[pp]=i; } memset(f,-63,sizeof(f)); f[0]=0; int ii=-1,ans=0,inf=f[1]; for(int h=0;h<=ma;h++) { if(!hd[h]) continue; int st[N],tt=0; for(int i=hd[h];i;i=nt[i]) st[++tt]=i; for(int i=tt;i>=1;i--) f[a[st[i]][1]+a[st[i]][2]]=max(f[a[st[i]][1]+a[st[i]][2]],f[a[st[i]][2]]+a[st[i]][0]); if(ans<f[h]) ans=f[h],ii=h; for(int i=tt;i>=1;i--) f[a[st[i]][1]+a[st[i]][2]]=inf; } //printf("%d\n",ans); if(ii>=0) { for(int i=hd[ii];i;i=nt[i]) st[++tt]=i; for(int i=tt;i>=1;i--) if(f[a[st[i]][1]+a[st[i]][2]]<f[a[st[i]][2]]+a[st[i]][0]) f[a[st[i]][1]+a[st[i]][2]]=f[a[st[i]][2]]+a[st[i]][0],pre[st[i]]=g[a[st[i]][2]],g[a[st[i]][1]+a[st[i]][2]]=st[i]; tt=0; int nw=g[ii]; while(nw) { an[++tt]=nw,nw=pre[nw]; } printf("%d\n",tt); for(int i=tt;i>=1;i--) printf("%d ",an[i]); } else puts("0"); return 0; }
CF28D Don't fear, DravDe is kind