1 条题解
-
0
第一种解法
定义状态 表示前 个数中取 个数和为 的方案数量。
设当前第 个数的值为 ,则有转移:
最终答案就是:
#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的方法来写这道题。
发现题目的数据范围很小,而平均值本身较难转移,可考虑将卡牌权值和作为一个维度进行存储和转移。
可以设 表示前 个数选 个数,和为 的方案数。
但是因为是01背包,所以可以用滚动数组优化掉第一个维度 (详情请自行学习01背包优化)。
用 表示已经拿了 张卡,卡的权值和为 时的选法种类。
可得到转移方程:
也就是取了第 张卡的时候的转移。
注意转移时第二重循环和第三重循环要倒序遍历 (详情请自行学习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
- 上传者