本文已参与「新人创作礼」活动,一起开启掘金创作之路。
@TOC
Codeforces Round #717 (Div. 2)-C. Baby Ehab Partitions Again
传送门 Time Limit: 2 seconds Memory Limit: 256 megabytes
Problem Description
Baby Ehab was toying around with arrays. He has an array of length . He defines an array to be good if there's no way to partition it into subsequences such that the sum of the elements in the first is equal to the sum of the elements in the second. Now he wants to remove the minimum number of elements in so that it becomes a good array. Can you help him?
A sequence is a subsequence of an array if can be obtained from by deleting some (possibly zero or all) elements. A partitioning of an array is a way to divide it into subsequences such that every element belongs to exactly one subsequence, so you must use all the elements, and you can't share any elements.
Input
The first line contains an integer () — the length of the array .
The second line contains integers , , , () — the elements of the array .
Output
The first line should contain the minimum number of elements you need to remove.
The second line should contain the indices of the elements you're removing, separated by spaces.
We can show that an answer always exists. If there are multiple solutions, you can print any.
Sample Input
4
6 3 9 12
Sample Onput
1
2
Note
In the first example, you can partition the array into and , so you must remove at least element. Removing is sufficient.
In the second example, the array is already good, so you don't need to remove any elements.
题目大意
给你个数,让你去掉尽可能少的数,使得剩下的数不能被分成和相等的两份。 和相等的两份是指第一份中的所有的元素的和等于第二份中所有的元素的和。
输出描述
这一题保证必定有解。
第一行输出至少需要去除的数的个数 第二行输出要去除的这些数的下标。
解题思路
这题答案只能是或。
- 如果本来就不能分成两份,那么只需要去除个数,即答案是。
- 如果本来能够分成和相等的两份,那么就说明这些数的和是偶数(这些数的和是奇数的话,是不可能分成和相等的两组的)。然后就看这些数中有没有一个奇数。
- 如果这些数中包含奇数,我们只需要把这一个奇数去掉,剩下的数的和就变成了奇数,就不能分成和相等的两组。
- 否则这些数中都是偶数的话,就所有数分别除以,不影响分配结果(如果除以之前能分成和相等的两组的话,那么都除以之后他们的和还相等)。直到含有奇数为止,就去掉这个奇数,即为答案。
那么问题就是如何快速确定最初的数组能不能分成连个和相同的数组,用01背包即可解决。
我们用一个类型的数组来表示前个数的和能不能是。 那么当前个数的和能为时,就不加上这个(第个)数,和还是。 或者前个数的和正好能组成i,那么加上这个数,总和正好是。 状态转移方程:dp[i][j]=dp[i-1][j]|dp[i-1][j-a[i]]
AC代码
#include <bits/stdc++.h>
using namespace std;
#define fi(i, l, r) for (int i = l; i < r; i++)
#define cd(a) scanf("%d", &a)
typedef long long ll;
int a[111]={0};
bool dp[111][111111]={0};//dp[i][j]表示前i个能不能正好为j
int main()
{
int n;
cin>>n;
int sum=0;//sum代表这n个数的总和
fi(i,0,n)//for(int i=0;i<n;i++)
cd(a[i]),sum+=a[i];//scanf("%d", &a[i]),sum+=a[i]
if(sum%2)//如果总和是奇数,直接就不能分成和相等的两组,去掉0个数即可
{
puts("0");
return 0;
}
sum/=2;//否则要找这n个数中,能不能找到一些数,他们的和是sum/2。如果能找到,就说明可以分成相等的两组
for(int i=0;i<n;i++)//初始化dp数组
{
dp[0][a[i]]=1;
}
for(int i=1;i<=n;i++)//前i个数
{
for(int j=sum;j>=a[i];j--)//和能不能是j
{
dp[i][j]=dp[i-1][j]|dp[i-1][j-a[i]];
}
}
if(!dp[n][sum])//如果原本的数就不能分成和相等的2份
{
puts("0");//直接去掉0个元素即可
return 0;
}
puts("1");//否则需要去掉一个元素
while(1)
{
fi(i,0,n)//for(int i=0;i<n;i++)
{
if(a[i]%2)//找到了一个奇数
{
printf("%d\n",i+1);//去掉这个奇数,剩下的数的和就是奇数,就不能分成两组了
return 0;
}
}
fi(i,0,n)//全部除以2
{
a[i]/=2;
}
}
return 0;
}
同步发文于我的CSDN,原创不易,转载请附上原文链接哦~
Tisfy:letmefly.blog.csdn.net/article/det…