题意:
最少删去多少个元素使得数列分成的两个子序列的和不相等;
思路:
首先求得序列的最大公约数zd,让序列元素都模zd模后必有一个奇数
,然后求和;
对整个数列的和做奇偶情况讨论
-
和为奇,则不需要删除元素;
-
和为偶:
用dp取判断这个序列最大能不能取到总和的二分之一(也就是分为两个子序列后和是否相等),也就是背包问题,序列的每个元素所占的空间为a[i],价值为a[i],背包容量为sum / 2;
(如果取得的最大价值为sum / 2,则我们需要删除一个元素,删除那个奇数即可,否则不需要删除任何数)
Code:
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <string>
#include <algorithm>
#include <queue>
#include <utility>
#include <stack>
#include <map>
#include <vector>
#include <set>
#include <iomanip>
#define hz020 return
#define mes memset
#define mec memcpy
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int>pii;
const int N = 110;
const int null = 0x3f3f3f3f;
const ll mod = 998244353;
int n;
int a[N];
int dp[N * 2000];
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
int main()
{
scanf("%d",&n);
int sum = 0;
for(int i = 1;i <= n;i ++) scanf("%d",&a[i]);
int zd = a[1];
for(int i = 2;i <= n;i ++) zd = gcd(zd,a[i]);
int iid = 0;
for(int i = 1;i <= n;i ++)
{
a[i] /= zd;
sum += a[i];
if(a[i] & 1) iid = i;
}
if(sum & 1) printf("0\n");
else
{
for(int i = 1;i <= n;i ++)
{
for(int j = sum / 2;j >= a[i];j --)
{
dp[j] = max(dp[j],dp[j -a[i]] + a[i]);
}
}
if(dp[sum / 2] == sum / 2)
{
printf("1\n%d\n",iid);
}
else
{
printf("0\n");
}
}
hz020 0;
}