1. 程式人生 > >NOIP模擬——偷書(讀書人的事,那能叫偷嗎?)

NOIP模擬——偷書(讀書人的事,那能叫偷嗎?)

價值 tput sample using title output 書籍 oid ane

題目

在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 ,所有書籍的價值的絕對值<=10^9

看到k小於等於10就應該想到狀壓dp的

dp[i][j]表示當前在第i個,狀態為j的最優解,因為每次向後遞推一個,我們只需要維護最後一個是否選了,並且判斷現在這個選不選

結果被數組大小給卡了,真是那啥了那啥

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define
ll long long 4 int v[1055],n,k,b,a,num[1024]; 5 ll dp[1055][1024],sum; 6 inline void getn(){ 7 for(int i=0;i<1024;i++) 8 { 9 int t=i,tot=0; 10 while(t) 11 { 12 if(t&1) 13 { 14 tot++; 15 } 16 t/=2; 17
} 18 num[i]=tot; 19 } 20 } 21 inline bool judge(int k) 22 { 23 return !(num[k]<a||num[k]>b); 24 } 25 int main(){ 26 scanf("%d%d%d%d",&n,&k,&a,&b); 27 getn(); 28 for(int i=1;i<=n;i++) 29 { 30 scanf("%d",&v[i]);sum+=v[i]; 31 } 32 for(int i=0;i<(1<<k);i++) 33 { 34 for(int j=0;j<k;j++) 35 { 36 if(i&(1<<j)) dp[k][i]+=v[k-j]; 37 } 38 } 39 for(int i=k+1;i<=n;i++) 40 { 41 for(int j=0;j<(1<<k);j++) 42 { 43 if(!judge(j)) continue; 44 int st=j; 45 st>>=1; 46 if(j&1) 47 { 48 int sta=st+(1<<k-1); 49 dp[i][j]=dp[i-1][sta]+v[i]; 50 if(judge(st)) dp[i][j]=max(dp[i][j],dp[i-1][st]+v[i]); 51 } 52 else 53 { 54 int sta=st+(1<<k-1); 55 dp[i][j]=dp[i-1][st]; 56 if(judge(sta)) dp[i][j]=max(dp[i][j],dp[i-1][sta]); 57 } 58 } 59 } 60 ll ans=-1000000000000; 61 for(int i=0;i<(1<<k);i++) 62 { 63 if(judge(i)) 64 ans=max(ans,dp[n][i]); 65 } 66 cout<<ans-sum+ans<<endl; 67 return 0; 68 }

NOIP模擬——偷書(讀書人的事,那能叫偷嗎?)