2018.10.01【校內模擬】偷書(狀壓DP)
阿新 • • 發佈:2018-12-13
描述
在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,啊。
思路:
搞明白是狀壓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;
}