1 条题解

  • 0
    @ 2022-11-19 20:22:49

    第一种解法

    定义状态 f(i,j,k)f(i, j, k) 表示前 ii 个数中取 jj 个数和为 kk 的方案数量。

    设当前第 ii 个数的值为 xx,则有转移:

    f(i,j,k)=l=0i1f(l,j1,kx)f(i,j,k) = \sum_{l=0}^{i-1} f(l, j - 1, k - x)

    最终答案就是:

    i=1nj=1nf(i,j,j×A)\sum_{i=1}^n \sum_{j=1}^n f(i, j, j\times A)
    #include<iostream>
    const int N = 60;
    long long f[N][N][N * N];
    int x[N];
    int main(){
        int n, a;
        std::cin >> n >> a;
        f[0][0][0] = 1;
        for(int i = 1; i <= n; i++)
            std::cin >> x[i];
        for(int i = 1; i <= n; i++){
            for(int j = 0; j < i; j++){
                for(int l = 0; l < i; l++){
                    for(int k = x[i]; k <= a * n; k++){
                        f[i][j + 1][k] += f[l][j][k - x[i]];
                    }
                }
            }
        }
        long long res = 0;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++){
                res += f[i][j][j * a];
            }
        }
        std::cout << res;
    }
    

    第二种解法

    每张卡片只有选和不选这两种状态,因此可以用01背包dp的方法来写这道题。

    发现题目的数据范围很小,而平均值本身较难转移,可考虑将卡牌权值和作为一个维度进行存储和转移。

    可以设 f(i,j,k)f(i,j,k) 表示前 ii 个数选 jj 个数,和为 kk 的方案数。

    但是因为是01背包,所以可以用滚动数组优化掉第一个维度 (详情请自行学习01背包优化)。

    f(i,j)f(i,j) 表示已经拿了 ii 张卡,卡的权值和为 jj 时的选法种类。

    可得到转移方程:

    f(i,j)=f(i1)(jx[i])f(i,j) = f(i - 1)(j - x[i])

    也就是取了第 ii 张卡的时候的转移。

    注意转移时第二重循环和第三重循环要倒序遍历 (详情请自行学习01背包优化)。

    #include<iostream>
    #include<algorithm>
    #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> PII;
    int x[110];
    ll f[60][3000];//一维表示取了多少个,二维表示总共的值是多少
    int main() {
        IOS;
        int n, a; cin >> n >> a;
        for (int i = 1; i <= n; i++) {
            cin >> x[i];
        }
        f[0][0] = 1;
        for (int i = 1; i <= n; i++) {
            for (int j = i; j >= 1; j--) {
                for (int k = n * a; k >= x[i]; k--) {
                    f[j][k] += f[j - 1][k - x[i]];
                }
            }
        }
        ll ans = 0;
        for (int i = 1; i <= n; i++) {
            ans += f[i][a * i];
        }
        cout << ans << endl;
    }
    ​
    
    • 1

    信息

    ID
    81
    时间
    1000ms
    内存
    256MiB
    难度
    4
    标签
    递交数
    2
    已通过
    1
    上传者