题意:
一个n长的序列,每个位置都有一个值w,每次连续的M个最多只能取Q个,问如何取使得获得最多的价值。
题解:
这题类似背包,对应每连续的序列进行转移到下个连续的序列,对于新加进来的位置有两个决策,一是取,二是不取。例如 1010,转到下个序列为0100,最后一位是新加进来的考虑取或不取的状态。于是可以这样设置dp[i][s],表示以i为结尾的M个连续序列选取的情况状态为s,获得的最大值。
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<queue> #include<map> #include<set> #define B(x) (1<<(x)) using namespace std; typedef long long ll; void cmax(int& a,int b){ if(b>a)a=b; } void cmin(int& a,int b){ if(b<a)a=b; } void cmax(ll& a,ll b){ if(b>a)a=b; } void cmin(ll& a,ll b){ if(b<a)a=b; } void add(int& a,int b,int mod){ a=(a+b)%mod; } void add(ll& a,ll b,ll mod){ a=(a+b)%mod; } const int oo=0x3f3f3f3f; const ll OO=0x3f3f3f3f3f3f3f3f; const ll MOD=1000000007; const int maxn=105; const int maxm=10000005; int dp[1005][B(10)+5]; int w[1005],ok[B(10)+5]; int main(){ //freopen("E:\\read.txt","r",stdin); int N,M,Q,ans; while(scanf("%d%d%d",&N,&M,&Q)!=EOF){ memset(dp,-1,sizeof dp); memset(ok,0,sizeof ok); for(int i=1;i<=N;i++)scanf("%d",&w[i]); if(N<M) M=N; int full=B(M)-1; for(int s=0;s<=full;s++){ int cnt=0,sum=0; for(int i=0;i<M;i++)if(s&B(i)){ cnt++; sum+=w[M-i]; } if(cnt<=Q){ dp[M][s]=sum; ok[s]=1; } } for(int i=M+1;i<=N;i++){ for(int s=0;s<=full;s++)if(dp[i-1][s]!=-1){ int s1=((s<<1)&full); int s2=((s<<1|1)&full); if(ok[s1]) cmax(dp[i][s1],dp[i-1][s]); if(ok[s2]) cmax(dp[i][s2],dp[i-1][s]+w[i]); } } ans=0; for(int s=0;s<=full;s++) cmax(ans,dp[N][s]); printf("%d\n",ans); } return 0; } /* 3 5 4 1 10 100 3 5 2 1 10 100 */