21.09.13模拟 分割金币

给定n个数,要求分成两堆,使得两堆的和的差值最小的差值和最小差值方案数
一遍背包即可,求出f_i=凑出和为i的一堆金币的方案数,那么凑出tot-f_i的方案数也会是f_i
贪心的从平均分配到不平均分配找即可

#include<iostream>
#include<cstdio>
#define rep(i,j,k) for(register int i(j);i<=k;++i)
#define drp(i,j,k) for(register int i(j);i>=k;--i)
#define bug cout<<"~~~~~~~~~~~~~"<<'
';
#define bugout(x) cout<<x<<endl;
typedef long long lxl;
template<typename T>
inline T  max(T &a, T &b) {
	return a > b ? a : b;
}
template<typename T>
inline T  min(T &a, T &b) {
	return a < b ? a : b;
}

inline char gt() {
	static char buf[1 << 21], *p1 = buf, *p2 = buf;
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
template <typename T>
inline void  read(T &x) {
	register char ch = gt();
	x = 0;
	int w(0);
	while(!(ch >= '0' && ch <= '9'))w |= ch == '-', ch = gt();
	while(ch >= '0' && ch <= '9')x = x * 10 + (ch & 15), ch = gt();
	w ? x = ~(x - 1) : x;
}
template <typename T>
inline void out(T x, char cc) {
	if(x < 0) x = -x, putchar('-');
	char ch[20];
	int num(0);
	while(x || !num) ch[++num] = x % 10 + '0', x /= 10;
	while(num) putchar(ch[num--]);
	putchar(cc);
}
const int N = 1007;
const int M = 257 * 1007;
int n, tot, a[N];
int f[M];
int main() {
	freopen("divgold.in", "r", stdin);
	freopen("divgold.out", "w", stdout);
	read(n);
	rep(i, 1, n) {
		read(a[i]);
		tot += a[i];
	}
	f[0] = 1;
	rep(i, 1, n)
	drp(j, tot, a[i]) {
		f[j] = (f[j] + f[j - a[i]]) % 1000000;
	}//±³°ü 
	int num = 0, t = 0;
	drp(j, tot/2,0) {
		if(f[j]) {
			t = tot - 2 * j;
			num = f[j];
			break;
		}
	}
	out(t, '
');
	out(num, '
');
	return 0;
}

本文来自博客园,作者:{2519},转载请注明原文链接:https://www.cnblogs.com/QQ2519/p/15376068.html

原文地址:https://www.cnblogs.com/QQ2519/p/15376068.html