题目描述
输入
第一行2个正整数n,m表示有n件事它开始拥有的精力
第n行,每行两个数,表示需要精力和可以获得的信誉
接下来n-1行一个数表示了他真香了哪件事
每次真香对下一次真香有影响
输出
第一行为开始时可以获得的最多信誉
接下来n-1行表示他真香了某件事后可以获得的最多信誉
输入样例
5 20
7 1
1 1
13 1
1 9
1 16
1
4
2
3
输出样例
27
27
18
17
16
说明
1~3:n,m<=100
3~5:n<=1000,m<=5000
6~10:n<=4000,m<=10000
其他数均为正整数,且不大于10000
题解:
把真香操作倒过来看,而最后一次就只有一个数了,那就看一下这个数可不可以放到 0 1 背包中
而对于每次减少的真香操作,就相当于将一个数加入 0 1 背包中
Code
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#define LL long long
#define ull unsigned LL
#define db double
#define ldb long db
#define re register
using namespace std;
const int N=1e6+100,M=2020;
struct sb
{
int w,v;
} a[N];
int n,m,b[N],k[N],f[N],fg[N];
void put ( int wz ) { for ( int j=m;j>=a[wz].w;j-- ) f[j]=max ( f[j],f[j-a[wz].w]+a[wz].v ); }
int main ( )
{
scanf ( "%d %d",&n,&m );
for ( int i=1;i<=n;i++ ) scanf ( "%d %d",&a[i].w,&a[i].v );
for ( int i=1;i<n;i++ ) scanf ( "%d",&b[i] ),fg[b[i]]=1;
for ( int i=1;i<=n;i++ ) if ( !fg[i] ) put ( i ),k[n]=f[m];
for ( int i=n-1;i>=1;i-- ) put ( b[i] ),k[i]=f[m];
for ( int i=1;i<=n;i++ ) printf ( "%d\n",k[i] );
return 0;
}