题目大意:
集合中有若干个元素,若一个元素可以由任意其它元素构成,那么我们得到一个加等式。
问我们最多能够得到多少加等式。
解题思路:
首先我们考虑只使用一维dp[n]是否可做,其中n代表第几个数,发现无法转移。这时候尝试
dp[n][m],其中n代表第几个数,m代表走到某一个数后求和为m的总数。
dp[i][j] = dp[i - 1][j];
if (j == arrmv[i])dp[i][j] += 1;
if (j > arrmv[i])dp[i][j] += dp[i - 1][j - arrmv[i]];
其中arrmv表示输入数据的数组。
for (int j = 0; j<MAXM; j++)
if (arr[j])ans += dp[m - 1][j]-1;
最后得到输出。arr[j]表示输入中有第j个元素。-1是因为加多了本身。
废话:
这题有两个难点。首先是要得到这个状态,这里我只是无意中试了一下搭配出来这个状态,然后我们验证这个状态是否有无后验性。最后我们还要知道输出这里为什么需要-1.
#include <bits/stdc++.h>
#define OPEN 0
#define int long long
using namespace std;
const int MAXN = 35;
const int MAXM = 3e4 + 10;
int dp[MAXN][MAXM];
int arr[MAXM];
int32_t main() {
#if OPEN
freopen("in.txt", "r", stdin);
#endif
int cas; cin >> cas;
while (cas--) {
int m; cin >> m;
vector<int> arrmv;
memset(arr, 0, sizeof(arr));
for (int i = 0; i<m; i++) {
int t; cin >> t;
arr[t] = 1;
arrmv.push_back(t);
}
memset(dp, 0, sizeof(dp));
dp[0][arrmv[0]] = 1;
for (int i = 1; i<(int)arrmv.size(); i++) {
for (int j = 0; j<MAXM; j++) {
dp[i][j] = dp[i - 1][j];
if (j == arrmv[i])dp[i][j] += 1;
if (j > arrmv[i])dp[i][j] += dp[i - 1][j - arrmv[i]];
}
}
int ans = 0;
for (int j = 0; j<MAXM; j++)
if (arr[j])ans += dp[m - 1][j]-1;
cout << ans << endl;
}
return 0;
}