【2018/10/01】T2 - 状态压缩 - 偷书

版权声明:虽然我只是个小蒟蒻但转载也请注明出处哦 https://blog.csdn.net/weixin_42557561/article/details/82916230

偷书 

在L的书架上,有 N本精彩绝伦的书籍,每本书价值不菲。 M 是一个书籍爱好者,他对 L 的书籍早就垂涎三尺。最后他忍受不了诱惑,觉得去偷 L 的书,为了迅速完成这件事,同时他不希望 L 很快发现书籍少了,他决定偷书时,对于任意连续的 k 本书,他最多选 B 本,最少选 A 本。现在他想知道怎么选出来的书本最后使得偷的书籍的价值和,与剩下的书籍价值和,差值最大。 

【 Input】 
第一行四个整数 n,k,a,b 
一行 N 个整数表示每本书的价值 
【 Output】 
一个整数表示答案 
【 Sample Input】 
2 1 0 1 
2 -2 
【 Sample Output】 

【 Hint】 
得到第一本书 得到的价值和是 2 
剩余的价值和是-2 
差值为 4 
【数据规模】 
对于 20%:n<=10 
对于另外 20%:a=0,b=k 
对于 100%:n<=1000,0<=a<=b<=k<=10 k<=n 所有书籍的价值的绝对值<=10^9 
 

分析

好难过……ldw老师欺骗了我的感情,我问他这句话“ 对于 100%:n<=1000,0<=a<=b<=k<=10 k<=n 所有书籍的价值的绝对值<=10^9 ”中的k<=10 k<=n 是什么鬼,他告诉我就是 k <= n ,然后。。。。。。就完全没想状压了

实际上就是 k<=10 

先来转化一下:偷的书籍的价值和,与剩下的书籍价值和,差值最大,也就是说 ans = 2*maxn - sum,由于sum是所有书的价值和,是一个定值,要 ans 最大也就是要 maxn 最大

那么我们定义 f [ i ] [ s ] 表示当前遍历到第 i 个点,包括 i 在内的 k 本书的状态在 s 里,此时的最优值(也就是偷到的书的价值之和最大的那个值)

转移的时候就从上一位 i - 1 转移到当前位

代码

#include<bits/stdc++.h>
#define ll long long
#define N 1009
#define in read()
using namespace std;
ll val[N],f[N][1025];
int n,k,a,b; 
bool leg[1025];
inline int read(){
	char ch;int res=0;
	while((ch=getchar())<'0'||ch>'9');
	while(ch>='0'&&ch<='9'){
		res=(res<<3)+(res<<1)+ch-'0';
		ch=getchar();
	}
	return res;
}
void init(){
	int status=(1<<10);
	for(int i=0;i<status;++i){
		int num=0,h=i;
		while(h){
			if(h&1) num++;
			h>>=1;
		}
		if(num>=a&&num<=b)  leg[i]=1;
	}
}
int main(){
	n=in;k=in;a=in;b=in;
	init();	int maxn=(1<<k);
	ll sum=0;
	for(int i=1;i<=n;++i) {scanf("%lld",&val[i]);sum+=val[i];}
	memset(f,-1,sizeof(f));
	for(int i=0;i<maxn;++i) f[0][i]=0;
	for(int i=1;i<=n;++i){
		for(int s=0;s<maxn;++s){
			if(leg[s]){
				if(f[i-1][(s>>1)]!=-1){
					if(s&1)	f[i][s]=max(f[i][s],f[i-1][s>>1]+val[i]);
					else f[i][s]=max(f[i][s],f[i-1][s>>1]);
				}
				if(f[i-1][(s>>1)|(1<<k-1)]!=-1){
					if(s&1)	f[i][s]=max(f[i][s],f[i-1][(s>>1)|(1<<k-1)]+val[i]);
					else f[i][s]=max(f[i][s],f[i-1][(s>>1)|(1<<k-1)]);
				}
			}
		}
	}
	ll ans=0;
	for(int i=0;i<maxn;++i){
		if(f[n][i]==-1) continue;
		ans=max(ans,f[n][i]);
	}
	printf("%lld",2*ans-sum);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42557561/article/details/82916230
今日推荐