2017-2018 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) B - Enlarging Enthusiasm dp好题

B - Enlarging Enthusiasm

感觉做到过好多的dp题都会和单调性结合在一起。

思路:dp[ s ][ pre ][ res ] 表示的是已选择了s,上一个是pre, 还有res 的分数的方案数。

然后再枚举下一个位置的时候,把其他位置的也减去这个值,因为是单调递增的所以不会多减,

这样就能保证pre 和 当前要枚举的 i 位置的差值永远为 a[ pre ] - a[ i ]

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define PLL pair<LL, LL>
#define PLI pair<LL, int>
#define PII pair<int, int>
#define SZ(x) ((int)x.size())
#define ull unsigned long long

using namespace std;

const int N = 1e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-8;
const double PI = acos(-1);

int n, m, ans, mx, a[12], dp[1<<12][12][701], num[1<<12];

int dfs(int s, int pre, int res) {
    if(res < 0) return 0;
    if(s+1 == 1<<n) return 1;
    if(~dp[s][pre][res]) return dp[s][pre][res];
    dp[s][pre][res] = 0;
    for(int i = 0; i < n; i++)
        if(!(s>>i&1)) dp[s][pre][res] += dfs(s|1<<i, i, res-max(a[pre]-a[i]+1, 0)*(n-num[s]));
    return dp[s][pre][res];
}
int main() {
    memset(dp, -1, sizeof(dp));
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
        mx = max(mx, a[i]);
    }
    for(int i = 1; i < (1<<n); i++)
        num[i] = num[i-(i&-i)] + 1;
    for(int i = 0; i < n; i++)
        if(a[i] != mx) ans += dfs(1<<i, i, m-(mx-a[i]+1)*n);
    printf("%d\n", ans);
    return 0;
}

/*
*/

猜你喜欢

转载自www.cnblogs.com/CJLHY/p/10231187.html