题解 P3010 【[USACO11JAN]分金Dividing the Gold】
此题一共有两个问题:
- 求金币分为两份的最小差值。
- 求分为最小差值时的方案数。
分步解答这两个问题。
第一个:
求两份金币的最小差值,那么我们很自然的想到,当两份金币相同时,差值最小。 那么题目就可以转化为,金币的价值最多能达到金币总价值的一半的多少。那么就是01背包了。
第二个:
直接求出第一问的金币价值的方案数即可。
下面贴下代码:
#include<bits/stdc++.h>
#define mod 1000000
using namespace std;
int n,a[350],tot,sum,f[500005];
long long dp[500005];
inline int read()
{
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
a[i]=read(),sum+=a[i];
tot=sum;
sum/=2;
for(int i=1;i<=n;i++)
for(int j=sum;j>=a[i];j--)
f[j]=max(f[j],f[j-a[i]]+a[i]);
printf("%d\n",tot-2*f[sum]);
dp[0]=1;
for(int i=1;i<=n;i++)
for(int j=tot;j>=a[i];j--)
dp[j]=(dp[j]+dp[j-a[i]])%mod;
printf("%lld",dp[f[sum]]);
return 0;
}