1. 程式人生 > >2018.10.01【校內模擬】偷書(狀壓DP)

2018.10.01【校內模擬】偷書(狀壓DP)

描述

在L的書架上,有N本精彩絕倫的書籍,每本書價值不菲。

M是一個書籍愛好者,他對L的書籍早就垂涎三尺。最後他忍受不了誘惑,覺得去偷L的書,為了迅速完成這件事,同時他不希望L很快發現書籍少了,他決定偷書時,對於任意連續的k本書,他最多選B本,最少選A本。現在他想知道怎麼選出來的書本最後使得偷的書籍的價值和,與剩下的書籍價值和,差值最大。

輸入

第一行四個整數 n,k,a,b

一行 N 個整數表示每本書的價值

輸出

一個整數表示答案

樣例輸入

2 1 0 1 2 -2

樣例輸出

4

提示

得到第一本書 得到的價值和是 2

剩餘的價值和是-2

差值為 4

資料範圍

對於 20%: n<=10 對於另外 20%: a=0,b=k 對於 100%: n<=1000,0<=a<=b<=k<=10, k <= n 所有書籍的價值的絕對值<=10^9

解析:

直接做顯然有毒啊。 多麼顯然的狀壓DP,k10k \leq 10啊。

思路:

搞明白是狀壓DP,這就是一道sb題啊。 直接預處理合法狀態然後轉移啊。

程式碼:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline
ll getint(){
	re ll num;
	re char c;
	re bool f=0;
	while(
!isdigit(c=gc()))f^=c=='-';num=c^48; while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48); return f?-num:num; } #define lowbit(x) (x&(-x)) inline int getbit(int x){ int cnt=0; while(x)x-=lowbit(x),++cnt; return cnt; } cs int N=1050; int n,k,a,b; ll f[N][N]; ll val[N]; bitset<N>
ok; ll sum; signed main(){ n=getint(); k=getint(); a=getint(); b=getint(); for(int re i=0;i<(1<<k);++i){ int res=getbit(i); if(a<=res&&res<=b)ok[i]=true; } for(int re i=1;i<=n;++i)sum+=val[i]=getint(); memset(f,-1,sizeof f); memset(f[0],0,sizeof f[0]); for(int re i=1;i<=n;++i){ for(int re j=0;j<(1<<k);++j){ if(!ok[j])continue; if(~f[i-1][j>>1]){ ll res=f[i-1][j>>1]; if(j&1)res+=val[i]; f[i][j]=max(f[i][j],res); } if(~f[i-1][(j>>1)|(1<<(k-1))]){ ll res=f[i-1][(j>>1)|(1<<(k-1))]; if(j&1)res+=val[i]; f[i][j]=max(f[i][j],res); } } } ll ans=-1000000000; for(int re i=0;i<(1<<k);++i)ans=max(ans,f[n][i]); cout<<ans*2-sum; return 0; }