Codeforces1516 C. Baby Ehab Partitions Again(思维,dp, 数学)

题目链接

题意:

给定一个序列, 若这个序列任意划分出的两个集合的和都不相等,那么称这个序列为好序列, 否则就判断是否可以通过删除某个值来将其转换为好序列

思路:

对整个序列求和得到sum, 若sum为奇数, 那么无论如何划分, 最后都会划分为一个奇数一个偶数的和, 所以此时该序列一定为好序列

若sum为偶数, 就需要判断是否存在一个子序列可以组成 s u m 2 \frac{sum}{2} 2sum 这里需要利用01背包进行处理判断是否可以构成 s u m 2 \frac{sum}{2} 2sum

一、若不能构成 s u m 2 \frac{sum}{2} 2sum

  1. 说明任意一个子序列的和都不会等于 s u m 2 \frac{sum}{2} 2sum 所以其互补的部分也一定不会等于 s u m 2 \frac{sum}{2} 2sum, 此时这个序列一定为好序列, 且不需要进行改变

二、若能构成 s u m 2 \frac{sum}{2} 2sum

  1. 若序列中含有奇数直接去掉一个奇数项即可
    假设可以将该序列分为 a i 1 {a_i}_1 ai1 + a i 2 {a_i}_2 ai2 + a i 3 {a_i}_3 ai3 + … + a i n {a_i}_n ain = a j 1 {a_j}_1 aj1 + a j 2 {a_j}_2 aj2 + a j 3 {a_j}_3 aj3 + … + a j n {a_j}_n ajn, 若原序列存在一个奇数项, 那么一定在两个序列中的某一个设为t 所以当删去t时 需要 另一侧将要分给删去的一侧 t 2 \frac{t}{2} 2t 又因为 t 为奇数, 所以我们无论如何都凑不出 t 2 \frac{t}{2} 2t 故删去t后一定为好序列

  2. 若序列中不含有奇数项, 那么就可以将 a i 1 {a_i}_1 ai1 + a i 2 {a_i}_2 ai2 + a i 3 {a_i}_3 ai3 + … + a i n {a_i}_n ain = a j 1 {a_j}_1 aj1 + a j 2 {a_j}_2 aj2 + a j 3 {a_j}_3 aj3 + … + a j n {a_j}_n ajn 转化为 x * ( a i 1 {a_i}_1 ai1 / x + a i 2 {a_i}_2 ai2 / x + … a i n {a_i}_n ain / x) = x * ( a j 1 {a_j}_1 aj1 / x + a j 2 {a_j}_2 aj2 / x + … a j n {a_j}_n ajn / x) (设 a 1 a_1 a1 - a n a_n an 的 gcd 为 x) 此时两边序列中至少有一个数为奇数, 若不存在奇数, 那么x一定还要乘以2, 即说明x不为 a 1 a_1 a1 - a n a_n an的gcd 与前提条件矛盾 这样我删除括号内含有奇数一侧的一个奇数项t, 就相当于删去了 t * x 若把x当成一个基数, 就会发现问题转化为了情况二的第一种情况, 删除数字所在另一侧一定是不存在 b 1 b_1 b1 b 2 b_2 b2 使得 b 1 b_1 b1 + b 2 b_2 b2 = t 2 \frac{t}{2} 2t 故只需要删除序列除以gcd后序列中出现的奇数即可

代码

#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using PII = pair<int, int>; 
const int N = 2e2 + 5, M = N * 2000;

int n;
int arr[N], dp[M];

int main()
{
    cin >> n;
    int sum = 0;
    for (int i = 1; i <= n; i++) {
        cin >> arr[i];
        sum += arr[i];
    }
    if (sum % 2) {
        cout << 0 << endl;
        return 0;
    }
    dp[0] = 1;
    for (int i = 1; i <= n; i++) {
        for (int j = sum; j >= arr[i]; j--) {
            dp[j] |= dp[j - arr[i]];
        }
    }
    if (!dp[sum / 2]) {
        cout << 0 << endl;
        return 0;
    }
    int q = arr[1];
    for (int i = 2; i <= n; i++)  {
        q = __gcd(q, arr[i]);
    }
    for (int i = 1; i <= n; i++) {
        arr[i] = arr[i] / q;
        if (arr[i] % 2) {
            cout << 1 << " " << i << endl;
            break; 
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/CUCUC1/article/details/116337236