jdoj 2171: Grape

题意

题目大意
一个农场的葡萄架上挂着n串葡萄,若取一个葡萄就会获得与其相应的美味值。对于连续的k串葡萄,最多取b串,最少取a串,
问能够获得的最大美味值为多少
数据范围
n<=10000,0<=a<=b<=k<=10

分析

考虑到在选到第i串葡萄时,影响到决策的只有i前面k串葡萄

f[i] [sta] 表示,考虑完第i串葡萄,后k串葡萄的状态为sta时的最大美味值

小技巧

  1. 看看n的范围,再想想我们的状态表示,可得,每次转移只需要前一个状态的信息,所以我们可以用i&1表示当前位置,那么(i+1)&1就是下一个位置

  2. 为了方便,不妨将这k串葡萄中的距离i最远的一串葡萄使用最后一个二进制位表示, 这样,我们在状态转移时>>1即可

只有在a <= cnt[sta] <= b时才考虑转移,转移时状态或上 1<<k,不转移时在合法的时候取最大值即可。

向前推进max

/
5 3 1 2
-1 1 2 -2 3
now_ans = 6
ans = 9
/

#include<cstdio>
#include<algorithm>
#include<string.h>
using namespace std;
const int N = 11;
const int MAX = (1<<N)-1;
#define lowbit (i&-i)

inline int read()
{
    int x=0,f=1;char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-')f=-1;ch = getchar();}
    while(ch >='0' && ch <='9'){x=(x<<1)+(x<<3)+ch-'0';ch = getchar();}
    return x*f;
}

int n,k,a,b,sum, max_k;
int f[2][1<<N], val[10000+9], cnt[1<<N];

int getone(int i) {
    int res = 0;
    while(i) ++res, i -= lowbit;
    return res;
}
int getval(int i) {
    int res = 0, pos = 1;
    while(i) {
        if(i&1) res += val[pos];
        i = i>>1, ++pos;
    }
    return res;
}

void pre() {
    n = read(), k = read(), a = read(), b = read();
    for(int i = 1; i <= n; i++) val[i] = read(), sum += val[i];
    max_k = (1<<k)-1;
    for(int i = 0; i <= max_k; i++) cnt[i] = getone(i);
    for(int i = 0; i <= max_k; i++) if(cnt[i]>=a && cnt[i]<=b) f[k&1][i] = getval(i);
}

void solve() {
    for(int i = k; i < n; i++) {//小技巧
        int o = (i&1), op = (o+1)&1;//o表示当前第一维,op表示下一个第一维
        memset(f[op], -0x3f, sizeof(f[op]));
        for(int j = 0; j <= max_k; j++) if(cnt[j]>=a && cnt[j]<=b) {
            int tmp1 = (j>>1), tmp2 = ((j|(1<<k))>>1);
            //tmp1表示不选,tmp2表示选
            if(cnt[tmp1]>=a && cnt[tmp1]<=b) f[op][tmp1] = max(f[op][tmp1], f[o][j]);//不减?
            if(cnt[tmp2]>=a && cnt[tmp2]<=b) f[op][tmp2] = max(f[op][tmp2], f[o][j]+val[i+1]);
        }
    }
    int ans = -2147483646;
    for(int j = 0; j <= max_k; j++) if(cnt[j]>=a && cnt[j]<=b) ans = max(ans, f[n&1][j]);
    printf("%d\n",ans*2-sum);
}
int main() {
    pre();
    solve();
    return 0;
}
02-11 02:41