Baby Ehab Partitions Again(dp,构造,位运算)

Baby Ehab Partitions Again

题面翻译

给定 n n n 长度的数组,定义一个数组是不好的,当且仅当可以把数组分成两个子序列,这两个子序列的元素之和相等。问使给定数组不是不好的最少删除几个元素,并输出被删除的元素的下标。

输入格式

The first line contains an integer $ n $ ( $ 2 \le n \le 100 $ ) — the length of the array $ a $ .

The second line contains $ n $ integers $ a_1 $ , $ a_2 $ , $ \ldots $ , $ a_{n} $ ( $ 1 \le a_i \le 2000 $ ) — the elements of the array $ a $ .

输出格式

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.

样例 #1

样例输入 #1

4
6 3 9 12

样例输出 #1

1
2

样例 #2

样例输入 #2

2
1 2

样例输出 #2

0

挺好的题,以前没做过这样的。一开始我的直觉是排序,贪心,类似二分图,n是偶数的话,某一个集合就拿走一个最大的和最小的。n是奇数就不会了。看到数据范围以为是多重循环?原来这种数据范围是背包

因为不好的数组要分成两个相等的子序列,所以如果sum(1~n的和)为奇,数组就是好的。

所以sum一定是偶数,用背包判断是否可以凑出sum/2 , 如果不能可以凑出来,那么答案就是0;

否则一定可以凑出来。又观察到,如果找到一个奇数,那么sum - 奇数 = 奇数,数组就一定是好的了。所以要找一个奇数,如果全是偶数呢?观察到,可以给所有数提公因子,求出所有数是2的几次幂,删掉最低次幂的数即可。

f [ i ] [ j ] f[i][j] f[i][j] 表示从前 i i i 个数中,能否凑出和为 j j j 的方案;

题解给了一种dp写法,不是很懂。

bool bad(vector<int> v)
{
    int s=0;
    for (int i:v)
    s+=i;
    if (s%2)
    return 0;
    bitset<200005> b;
    b[0]=1;
    for (int i:v)
	    b|=(b<<i);
    return b[s/2];
}
/*
A: 10min
B: 20min
C: 30min
D: 40min
*/ 
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <sstream>
#define pb push_back 
#define all(x) (x).begin(),(x).end()
#define mem(f, x) memset(f,x,sizeof(f)) 
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo_(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math,O3")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")

template<typename T>
ostream& operator<<(ostream& os,const vector<T>&v){for(int i=0,j=0;i<v.size();i++,j++)if(j>=5){j=0;puts("");}else os<<v[i]<<" ";return os;}
template<typename T>
ostream& operator<<(ostream& os,const set<T>&v){for(auto c:v)os<<c<<" ";return os;}
template<typename T1,typename T2>
ostream& operator<<(ostream& os,const map<T1,T2>&v){for(auto c:v)os<<c.first<<" "<<c.second<<endl;return os;}
template<typename T>inline void rd(T &a) {
    char c = getchar(); T x = 0, f = 1; while (!isdigit(c)) {if (c == '-')f = -1; c = getchar();}
    while (isdigit(c)) {x = (x << 1) + (x << 3) + c - '0'; c = getchar();} a = f * x;
}

typedef pair<int,int>PII;
typedef pair<long,long>PLL;

typedef long long ll;
typedef unsigned long long ull; 
const int N=2e5+10,M=1e9+7;
ll n,m,_;

// 2022-7-11 14:28:41

// 卡住了,不知道咋思考

// 2022-7-11 15:11:29 看题解学会了
int f[200010],a[N];
void solve(){
	cin>>n;
	ll sum=0;
	fo(i,1,n){
		cin>>a[i];
		sum+=a[i];
	}
	if(sum&1){
		puts("0");
		return ;
	}
	else{
		f[0]=1;
		sum/=2;
		for(int i=1;i<=n;i++){
			for(int j=sum;j>=a[i];j--){
				f[j] |= f[j-a[i]];
			}
		}
		if(!f[sum]){
			puts("0");
		}
		else{
			int pos,Max = N;
			fo(i,1,n){
				int x = a[i];
				int cnt = 0;
				while(x%2==0){
					x/=2;
					cnt++;
				}
				if(cnt<Max){
					Max = cnt;
					pos = i;
				}
			}
			cout<<1<<endl;
			cout<<pos<<endl;
		}
	}
}

int main(){
	solve();
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值