Codeforces 1516C. Baby Ehab Partitions Again(背包+思维)

传送门


题目大意

给出 n ( n ≤ 100 ) n( n \leq 100) n(n100)个数的序列 a i ( 1 ≤ a i ≤ 2000 ) a_i(1 \leq a_i \leq 2000) ai(1ai2000),若这个序列能被分成两部分且这两部分的和相等,称这个序列是不好的。最少删除几个数使得这个序列不是不好的。

解题思路

不难想到,若一个序列能分为两部分和相同的,那么所有数的和 s u m sum sum一定是偶数,然后如何判断初始的序列能否分成两部分呢?背包,每个物品选或者不选,判断最后能否凑成 s u m 2 \frac{sum}{2} 2sum

若能凑成,需要判断删除几个数,直觉判断删除一个数就可以(这部分无法证明,题解也没说如何证明),但这个数不能随便删,考虑序列是否有奇数:

  • 若序列至少有一个奇数,我们删除这个奇数后剩下序列的和一定是奇数,一定不是不好的序列。

  • 若序列全是偶数,注意到两部分存在一个求和的等式,对这个等式两边不断除以2,不影响“相等的结果”,因此只需要删除含有2的幂次最少的数。

#include <bits/stdc++.h>

using namespace std;
#define ENDL "\n"
typedef long long ll;
const double eps = 1e-8;
const int inf = 0x3f3f3f3f;
const int Mod = 1e9 + 7;
const int maxn = 2e5 + 10;

struct node {
    
    
    int id, val;
    int cnt;
} b[105];

bool cmp(node &p, node &q) {
    
     return p.cnt < q.cnt; }

int a[105];

bool d[105][maxn];

int main() {
    
    
    // freopen("in.txt","r",stdin);
    // freopen("out.txt", "w", stdout);
    // ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n, sum = 0;
    cin >> n;
    for (int i = 1; i <= n; i++) {
    
    
        cin >> a[i], sum += a[i];
        b[i].id = i;
        b[i].val = a[i];
    }
    if (sum & 1) {
    
    
        cout << "0" << ENDL;
        return 0;
    }
    int m = sum / 2;
    d[0][0] = 1;
    for (int i = 1; i <= n; i++) {
    
    
        for (int j = 0; j <= m; j++) {
    
    
            d[i][j] = d[i - 1][j];
            if (j >= a[i]) d[i][j] |= d[i - 1][j - a[i]];
        }
    }
    if (d[n][m]) {
    
    
        for (int i = 1; i <= n; i++) {
    
    
            if (a[i] & 1) {
    
    
                cout << 1 << ENDL << i << ENDL;
                return 0;
            }
        }
        for (int i = 1; i <= n; i++) {
    
    
            int x = b[i].val;
            while (x % 2 == 0) {
    
    
                x /= 2;
                b[i].cnt++;
            }
        }
        sort(b + 1, b + 1 + n, cmp);
        cout << 1 << ENDL;
        cout << b[1].id << ENDL;
    } else
        cout << 0 << ENDL;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44691917/article/details/116144735