CSP2019PJT3

作为一个退役的CSP-J选手,回想自己考场上就在这题上飞了…这道题送我告别CSP普及…

不扯远了,考虑在同一天将一个物品买一次又卖一次,小伟的钱没有任何变化(这个性质看似是废话,其实很有用),所以我们可以把一次在第i天买的一个物品在第j天卖掉拆成第i天买,第(i+1)天又卖出,第(i+1)天买,第(i+2)天又卖出…直到第(j-1)天买,第j天卖出,中间之所以可以增加买卖且做到与原来的操作等价,是因为前面的那个性质。

于是,只需要将这T天的买卖分开来看:将每次交易进行上文所述的操作后,第k天买的东西第(k+1)天就会卖掉。

所以,从第一天和第二天开始考虑:

第一天刚开始时小伟有M元钱,他能买的东西价格和不超过M,每件东西可以买任意件,买一件物品i因为第二天会卖出所以收益为 p 2 , i p_{2,i} p2,i

上面的描述,相信然你想到了完全背包。

继续看后面的每一天:除了开始有多少钱你不确定,其他和第一天的情况差别不大,所以也可以用完全背包。

每天完全背包复杂度是 O ( n A n s m a x ) O(nAns_{max}) O(nAnsmax),有T天,所以总复杂度是 O ( T n A n s m a x ) O(TnAns_{max}) O(TnAnsmax)。NOIP不是一两年前换了个少爷机吗, 只要不换回老爷机,(等等,CSP和NOIP毫无关系,所以没有“换回”这种说法) 1e8显然随便过

下面是参考程序:

#include
using namespace std;
template<class T>inline void read(T&a){
	char c=getchar();int f=1;a=0;
	while(c>'9'||c<'0'){if(c=='-') f=-1;c=getchar();}
	while(c<='9'&&c>='0') a=(a<<1)+(a<<3)+c-48,c=getchar();
	a*=f;
}
template<class T>void write(T a){
	if(a<0) putchar('-'),a=-a;
	if(a>9) write(a/10);
	putchar(a%10+48);
}
const int o=110;
int T,n,m,p[o][o],f[10010];
inline int max(int a,int b){return a>b?a:b;}
int main(){
//	freopen("souvenir.in","r",stdin);
//	freopen("souvenir.out","w",stdout);
	read(T);read(n);read(m);
	for(int i=1;i<=T;++i) for(int j=1;j<=n;++j) read(p[i][j]);
	for(int i=2;i<=T;++i){//以下为完全背包
		for(int j=1;j<=m;++j) f[j]=j;
		for(int j=1;j<=n;++j)
			for(int k=p[i-1][j];k<=m;++k)
				f[k]=max(f[k],f[k-p[i-1][j]]+p[i][j]);
		for(int j=1;j<=m;++j) f[j]=max(f[j],f[j-1]);
		m=f[m];//这一天的收益最大值成为下一天的背包容量
	}
	write(m);
	return 0;
}

你可能感兴趣的:(CSP2019PJT3)