1. 程式人生 > >NOIP模擬 偷書

NOIP模擬 偷書

col name read nbsp 希望 out set mat code

【題目描述】

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

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

【輸入格式】

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

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

【輸出格式】

一個整數表示答案

【樣例輸入】

2 1 0 1

2 -2

【樣例輸出】

4

【備註】

對於 20%:n<=10

對於另外 20%:a=0,b=k

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

【題目分析】

一看到k<=10,這麽小的數據簡直就是宣告這是一道狀壓DP的題,那麽就定義一個數組dp[i][j],其中i表示前i個,狀態為j(包含第i個)的最大價值,易得對於每個合法dp[i][j],均可從dp[i-1][j>>1]和dp[i-1][(j>>1)|(1<<k)]轉移而來,所以先預處理出所有合法情況(即1的個數大於等於a而小於等於b),最後掃一遍dp[n][k]即可。

 1 #include<iostream>
 2
#include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<algorithm> 6 #include<queue> 7 #include<cmath> 8 using namespace std; 9 typedef long long LL; 10 const LL MAXN=1<<11; 11 const LL INF=0x3f3f3f3f; 12 13 LL dp[1001][MAXN]; 14 LL n,k,a,b;
15 LL val[1001]; 16 bool che[MAXN]; 17 18 LL Read() 19 { 20 LL i=0,f=1; 21 char c; 22 for(c=getchar();(c>9||c<0)&&c!=-;c=getchar()); 23 if(c==-) 24 f=-1,c=getchar(); 25 for(;c>=0&&c<=9;c=getchar()) 26 i=(i<<1)+(i<<3)+c-0; 27 return i*f; 28 } 29 30 void pre() 31 { 32 for(LL i=0;i<=MAXN;++i) 33 { 34 LL t=i; 35 LL cnt=0; 36 while(t) 37 { 38 if(t&1) 39 cnt++; 40 t>>=1; 41 } 42 if(cnt>=a&&cnt<=b) 43 che[i]=true; 44 } 45 } 46 47 int main() 48 { 49 memset(dp,INF,sizeof(dp)); 50 n=Read(),k=Read(),a=Read(),b=Read(); 51 LL ans=-dp[0][0],inf=dp[0][0]; 52 pre(); 53 LL tot=0; 54 for(LL i=1;i<=n;++i) 55 val[i]=Read(),tot+=val[i]; 56 for(LL j=0;j<(1<<k);++j) 57 dp[0][j]=0; 58 LL cs=1<<k; 59 for(LL i=1;i<=n;++i) 60 { 61 for(LL j=0;j<cs;++j) 62 { 63 if(che[j]) 64 { 65 if(dp[i-1][j>>1]!=inf&&dp[i-1][(j>>1)|(1<<(k-1))]!=inf) 66 { 67 if(j&1) 68 dp[i][j]=max(dp[i-1][j>>1],dp[i-1][(j>>1)|(1<<(k-1))])+val[i]; 69 else 70 dp[i][j]=max(dp[i-1][j>>1],dp[i-1][(j>>1)|(1<<(k-1))]); 71 } 72 else 73 { 74 dp[i][j]=min(dp[i-1][j>>1],dp[i-1][(j>>1)|(1<<(k-1))]); 75 if(dp[i][j]==inf) 76 continue; 77 if(j&1) 78 dp[i][j]+=val[i]; 79 } 80 } 81 } 82 } 83 for(LL i=0;i<cs;++i) 84 { 85 if(dp[n][i]==inf) 86 continue; 87 ans=max(ans,dp[n][i]); 88 } 89 cout<<ans*2-tot; 90 return 0; 91 }

NOIP模擬 偷書