1 条题解
-
0
题意
给定一个整数数组。 定义数组第i位上的减操作:把和换成。 用表示减操作,可以表示为: $con(a, i) = [a_1, a_2, \cdots, a_{i - 1}, a_i - a_{i + 1}, a_{i + 2}, \cdots, a_n]$ 长度为的数组,经过次减操作后,就可以得到一个整数t。 例如数组经过如下操作可得到整数4: 现在给定数组以及目标整数,求完整操作过程。
解题思路
首先分析子问题划分,发现对答案贡献必为正,尝试将子问题划分为组成,但此思路因后续元素符号不确定而受阻。得到关键信息:贡献为正,贡献为负,其余元素符号不确定。贡献符号取决于合并次数,奇数次为负。题目等价于通过加减组合得。提出猜想:当时,正负可任意组合。以三个元素()为例:需与同号,先合并,再合并;需与异号,先合并,再合并。控制合并次数奇偶,可确定其贡献符号。最终问题转化为:为正,为负,正负任意组合得。由于,暴力不可行,利用数值范围,定义:前个元素组合结果为,第个元素贡献符号(正为,负为)。
标程
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #define ll long long #define ull unsigned long long using namespace std; const int INF = 0x3f3f3f3f; const int maxn = 20007; int dp[107][maxn], num[107], flag[maxn]; int main() { int n, t; cin >> n >> t; t += 10000; for (int i = 1; i <= n; i++) { scanf("%d", num + i); } dp[2][10000 + num[1] - num[2]] = -1; for (int i = 3; i <= n; i++) { for (int j = 20000 ; j > 0; j--) { if (j - num[i] >= 0 && dp[i - 1][j - num[i]] != 0) { dp[i][j] = 1; } if (j + num[i] <= 20000 && dp[i - 1][j + num[i]] != 0) { dp[i][j] = -1; } } } int now_i = n, now_num = t; while (now_i > 1) { flag[now_i] = dp[now_i][now_num]; now_num += -flag[now_i] * num[now_i]; now_i--; } int cnt = 0; for (int i = 2; i <= n; i++) { if (flag[i] > 0) { cout << i - cnt - 1 << endl; cnt++; } } for (int i = 2; i <= n; i++) { if (flag[i] < 0) { cout << 1 << endl; } } return 0; }
- 1
信息
- ID
- 723
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 8
- 已通过
- 1
- 上传者