Codeforces Round #717 (Div. 2) C Baby Ehab Partitions Again(思维)

题意:

给出一个数组,如果数组中其中一些数的和等于剩下数的和,那么数组就是坏的,问最小要删去几个数才能使得数组是好的。

题解:

如果数组的和 s u m sum sum为奇数,那么一定是好的。

如果为偶数,可以先用类似于背包的 d p dp dp求出是否有一些数相加为 s u m / 2 sum/2 sum/2

如果有,如果数组中存在奇数,那么删去这个奇数,就一定满足条件。如果不存在奇数,假设我要删去 x x x,那么如果 x / 2 x/2 x/2 存在,那么就得把先 x / 2 x/2 x/2 删去,把 x / 2 x/2 x/2 删去时,又得考虑 x / 4 x/4 x/4 ,以此类推,那么其实只要删去一直除 2 2 2 最快变为奇数的数,就一定满足条件。

证明:假设这个数是 x x x,那么这个数 x / 2 x/2 x/2 就一定不存在, 如果存在, x / 2 x/2 x/2 一直除2直到变为奇数的次数一定比 x x x 少,那最优解就不是 x x x了。所以一定不存在 x / 2 x/2 x/2 ,那么最后把 x x x删去就不可能使得两边的和还能相等。

代码:

#pragma GCC diagnostic error "-std=c++11"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=2e5+5;
const int inf=0x3f3f3f3f;
int dp[2][MAXN];
int a[MAXN];
int num[MAXN];
int main()
{
     
    int n;
    cin>>n;
    int sum=0;
    for(int i=1;i<=n;i++)
    {
     
        cin>>a[i];
        sum+=a[i];
        int temp=a[i];
        while(temp%2==0)
        {
     
            num[i]++;
            temp/=2;
        }
    }
    dp[1][0]=1;
    int f=1;
    for(int i=1;i<=n;i++)
    {
     
        for(int j=2e5;j>=0;j--)
        {
     
            if(dp[f][j])
            {
     
                dp[f^1][j+a[i]]=1;
                dp[f^1][j]=1;
            }
        }
        f^=1;
    }
    if(sum&1)
    {
     
        printf("%d\n",0);
    }
    else if(dp[f][sum/2]==0)
    {
     
        printf("%d\n",0);
    }
    else 
    {
     
        printf("%d\n",1);
        int ans=1e9;
        int pos;
        for(int i=1;i<=n;i++)
        {
     
            if(num[i]<ans)
            {
     
                ans=num[i];
                pos=i;
            }
        }
        printf("%d\n",pos);
    }
}

你可能感兴趣的:(思维)