687C

dp

以前做过 忘了。

想破脑袋不知道怎么设状态

dp[i][j][k]表示选到第i个硬币,当前和为j,能否弄出k

dp[i][j][k]|=dp[i-1][j][k]|dp[i-1][j][k-c[i]]|dp[i-1][j-c[i]][k-c[i]]

如果发现状态不行,就试着多加一维,也许就能搞定

#include<bits/stdc++.h>
using namespace std;
const int N = 510;
int n, k, pre;
int dp[2][N][N], c[N];
vector<int> ans;
int main()
{
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n;++i) scanf("%d", &c[i]);
    dp[pre][0][0] = 1;
    for(int x = 1; x <= n; ++x)
    {
        pre ^= 1;
        for(int i = 0; i <= k; ++i)
            for(int j = 0; j <= k; ++j)
            {
                dp[pre][i][j] = dp[pre ^ 1][i][j];
                if(i - c[x] >= 0)
                {
                    dp[pre][i][j] |= dp[pre ^ 1][i - c[x]][j];
                    if(j - c[x] >= 0)
                        dp[pre][i][j] |= dp[pre ^ 1][i - c[x]][j - c[x]];
                }
            }
    }
    for(int i = 0; i <= k; ++i) if(dp[pre][k][i])
        ans.push_back(i);
    printf("%d\n", ans.size());
    sort(ans.begin(), ans.end());
    for(int i = 0; i < ans.size(); ++i) printf("%d ", ans[i]);
    return 0;
}

时间: 2024-10-13 21:27:09

687C的相关文章

Codeforces 687C The Values You Can Make(DP)

题目大概说给n个各有价值的硬币,要从它们中选出若干个组合成面值k,而要求的是各个方案里这些选出的硬币能组合出来的面值有哪些. 有点绕.. dp[i][j][k]表示前i个硬币中 能否 组合成面值j且选出的硬币能组合成面值k 转移要考虑全面..三个方向转移,第i个不选.第i个选但不参与选出硬币去组合成k.第i个选且参与选出硬币去组成成k 1 #include<cstdio> 2 using namespace std; 3 4 bool d[555][555][555]; 5 int main(

CodeForces 687C The Values You Can Make

$dp$,背包. $f[i][j][s]$表示前$i$个物品,凑出$j$价格的情况下,能否凑出$s$价格,$f[i][j][s]=1$表示能,否则不能. 转移很简单:如果$f[i][j][s]=1$,那么$f[i+1][j][s]=1$,$f[i+1][j+c[i]][s]=1$,$f[i+1][j+c[i]][s+c[i]]=1$.最后将$f[n][k][s]=1$的$s$都输出就可以了. $f[500][500][500]$内存会炸,第一维可以用滚动数组优化. #pragma comment

CodeForces 687C The Values You Can Make(动态规划)

这个也可以说是一个01背包了,里面也有一些集合的思想在里面,首先dp方程,dp[i][j]代表着当前数值为i,j能否被构成,如果dp[i][j] = 1,那么dp[i+m][j] 和 dp[i+m][j+m] = 1,所以转移方程就写出来了,但是注意我们只能从后向前转移,也就是说我们一定要用选上一个数的状态,因为这里是01背包,每一个数只能选一次,如果正着选就是完全背包了. 代码如下: #include<iostream> #include<cstdio> #include<