C - Baby Ehab Partitions Again
题意:给定一个序列,问如何在删除最少数字的情况下将它们分为两组,并时两组的和相等。
思路:分类讨论
1.整个数组结果为奇数时,不用删除
2.结果为偶数时,判断能不能凑出满足条件的两个分组(通过01背包算法就可以判断,01背包中的价值等于大小的情况下,就可以判断在最大背包大小的情况下的最大值是否等于这个大小)
2.1不能,则不用删除
2.2能,则将数组的每个元素同时除2,直到出现1为止,删除这个数字就可以了。这是因为整个数组不断同时/2之后结果还是不变,由之前的步骤可知,如果一个数组存在奇数和偶数,且结果为偶数,且需要删除的情况下,只需要删除一个奇数即可,因此这一步将整个数组的每个元素不断同时/2之后(可直接除以整个数组的GCD一步到位),就会在满足条件的情况下出现奇数,这样将这个奇数删除就可以了。
#include <iostream>
#include <queue>
#include <algorithm>
#include <map>
#include <math.h>
using namespace std;
#define ll long long
const int maxn = 2*1e3+110;
const int INF = 1e9;
const int mod = 1e9+7 ;
ll a[maxn];
ll b[maxn*100];
int c[maxn];
int main(){
int t=1;
//cin>>t;
while(t--){
int n,te;
cin>>n;
ll sum =0;
for(int i=1;i<=n;i++){
cin>>a[i];
c[a[i]]++;
sum+=a[i];
}
if(sum%2){
cout<<0<<endl;
}
else{
int ban = sum/2;
for(int i=1;i<=n;i++){
for(int j=ban;j>=a[i];j--){
b[j] = max(b[j],b[j-a[i]]+a[i]);
}
}
if(b[ban]==ban){
ll gcd = a[1];
for(int i=2;i<=n;i++) gcd = __gcd(gcd,a[i]);
for(int i=1;i<=n;i++){
a[i]/=gcd;
}
for(int i=1;i<=n;i++){
if(a[i]%2==1){
cout<<1<<endl;
cout<<i<<endl;
break;
}
}
}
else{
cout<<0<<endl;
}
}
}
}