AcWing318 划分大理石

题目描述

有价值分别为 \(1..6\) 的大理石各 \(c_1\sim c_6\) 块,现要将它们分成两部分,使得两部分价值之和相等,问是否可以实现。

其中大理石的总数不超过 \(20000\)

大体思路

一类常见的多重背包模型。注意由于两部分的价值之和 \(sum=\sum i\times a_i\),价值相等则必然说明 \(sum\) 为偶数。

然后,我们可以将问题看成:有面额 \(1\sim 6\) 的纸币 \(a_1\sim a_6\) 张,问能否组成面额 \(\dfrac {sum} 2\)。直接使用多重背包二进制拆分即可。

代码

#include <bits/stdc++.h>
using namespace std;
#define rep(ii,aa,bb) for(re int ii = aa; ii <= bb; ii++)
#define Rep(ii,aa,bb) for(re int ii = aa; ii >= bb; ii--)
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair<int, int> PII;
const int maxn = 2e5 + 5;
namespace IO_ReadWrite {
	#define re register
	#define gg (p1 == p2 && (p2 = (p1 = _buf) + fread(_buf, 1, 1<<21, stdin), p1 == p2) ? EOF :*p1++)
	char _buf[1<<21], *p1 = _buf, *p2 = _buf;
	template <typename T>
	inline void read(T &x){
		x = 0; re T f=1; re char c = gg;
		while(c > 57 || c < 48){if(c == '-') f = -1;c = gg;}
		while(c >= 48 &&c <= 57){x = (x<<1) + (x<<3) + (c^48);c = gg;}
		x *= f;return;
	}
	inline void ReadChar(char &c){
		c = gg;
		while(!isalpha(c)) c = gg;
	}
	template <typename T>
	inline void write(T x){
		if(x < 0) putchar('-'), x = -x;
		if(x > 9) write(x/10);
		putchar('0' + x % 10);
	}
	template <typename T>
	inline void writeln(T x){write(x); putchar('\n');}
}
using namespace IO_ReadWrite;
int n, c[10], w[10], sum;
bool f[maxn];
inline void work(int V) {
	Rep(j, sum, V) f[j] |= f[j - V];
}
int main () {
	n = 6;
	while(1) {
		rep(i, 1, n) read(c[w[i] = i]);
		if(!(c[1] + c[2] + c[3] + c[4] + c[5] + c[6])) return 0;
		sum = 0;
		rep(i, 1, n) sum += i * c[i];
		if(sum & 1) {
			puts("Can't");
			continue;
		}
		memset(f, 0, sizeof f);
		f[0] = 1;
		rep(i, 1, n) {
			for(int k = 1; k <= c[i]; c[i] -= k, k <<= 1) work(k * w[i]);
			if(c[i]) work(c[i] * w[i]);
		}
		puts(f[sum >> 1] ? "Can" : "Can't");
	}
	
	return 0;
}
posted @ 2022-04-05 17:16  Mars_Dingdang  阅读(55)  评论(0)    收藏  举报