1 条题解

  • 0
    @ 2025-4-8 16:17:48

    题意

    给定一个整数数组a1,a2,,ana_1, a_2, \cdots, a_n。 定义数组第i位上的减操作:把aia_iai+1a_{i + 1}换成aiai+1a_i - a_{i + 1}。 用con(a,i)con(a, i)表示减操作,可以表示为: $con(a, i) = [a_1, a_2, \cdots, a_{i - 1}, a_i - a_{i + 1}, a_{i + 2}, \cdots, a_n]$ 长度为nn的数组,经过n1n - 1次减操作后,就可以得到一个整数t。 例如数组[12,10,4,3,5][12, 10, 4, 3, 5]经过如下操作可得到整数4: con([12,10,4,3,5],2)=[12,6,3,5]con([12, 10, 4, 3, 5], 2) = [12, 6, 3, 5] con([12,6,3,5],3)=[12,6,2]con([12, 6, 3, 5], 3) = [12, 6, -2] con([12,6,2],2)=[12,8]con([12, 6, -2], 2) = [12, 8] con([12,8],1)=[4]con([12, 8], 1) = [4] 现在给定数组以及目标整数,求完整操作过程。

    解题思路

    首先分析子问题划分,发现a1a_1对答案贡献必为正,尝试将子问题划分为a2,a3,,ana_2, a_3, \cdots, a_n组成ta1t - a_1,但此思路因后续元素符号不确定而受阻。得到关键信息:a1a_1贡献为正,a2a_2贡献为负,其余元素符号不确定。ana_n贡献符号取决于合并次数,奇数次为负。题目等价于a1ana_1 \sim a_n通过加减组合得tt。提出猜想:当n3n \geq 3时,a3ana_3 \cdots a_n正负可任意组合。以三个元素ai1,ai,ai+1a_{i-1}, a_i, a_{i+1}i>3i > 3)为例:需ai+1a_{i+1}aia_i同号,先合并ai1,aia_{i-1}, a_i,再合并ai+1a_{i+1};需ai+1a_{i+1}aia_i异号,先合并ai,ai+1a_i, a_{i+1},再合并ai1a_{i-1}。控制ai+1a_{i+1}合并次数奇偶,可确定其贡献符号。最终问题转化为:a1a_1为正,a2a_2为负,a3ana_3 \sim a_n正负任意组合得kk。由于n=100n = 100,暴力不可行,利用数值范围,定义dp[i][j]dp[i][j]:前ii个元素组合结果为jj,第ii个元素贡献符号(正为11,负为1-1)。

    标程

    #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
    上传者