【SSL】20210812-B
题目描述
输入格式
第一行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
解题思路
首先看到题,马上就想到了01背包,但是一看数据大小,普通的01背包肯定过不了。所以我们可以边输入边处理,时间复杂度为O(nm)O(nm)O(nm)。
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#define sco 10010
using namespace std;
#define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,1<<15,stdin),S==T))?EOF:*S++)
char buffer[1<<15],*S=buffer,*T=buffer;
int a[sco],b[sco],f[sco][4010],w[sco],c[sco],n,m,tot(0);
int read()
{
int m=0,n=1;
char ch;
ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
n=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
m=m*10+ch-'0';
ch=getchar();
}
return m*n;
}
int main()
{
n=read();
m=read();
for(int i=1;i<=n;++i)
{
a[i]=read();
b[i]=read();
tot+=i;
}
for(int i=1;i<n;++i)
{
int x;
x=read();
tot-=x;
w[n-i+1]=a[x];
c[n-i+1]=b[x];
}
w[1]=a[tot];
c[1]=b[tot];
for(int i=1;i<=m;++i)
{
for(int j=1;j<=n;++j)
{
if(w[j]<=i)
f[i][j]=max(f[i][j-1],f[i-w[j]][j-1]+c[j]);
else
{
f[i][j]=f[i][j-1];
}
}
}
for(int j=n;j>0;--j)
{
printf("%d\n",f[m][j]);
}
return 0;
}