https://www.codechef.com/KOL15MOS/problems/KOL1502 印度的区域赛,很遗憾赛后不能提交了。。。
原本一直找不到正确的AC打开方式,实在也算道脑洞题吧。下午课上突然想到如何解题了,这种灵光一现的时刻多一点该有多好。。。
一组数据,从中选取一部分数,s=max(这部分数-剩下的数,剩下的数-这部分数),即abs(这部分数-剩下的数)。求所有选取方式的s之和。
一开始一直画画画,想找出什么规律,但是发现345和349这两种情况是的加减是不一样的,所以没有规律可循。然后就懵了两天。
今天课上突然想到,如果给一组数前面加上正负号,那么其中的正数之和如果小于s的一半,最后的结果就是负数。那么这个负数就要被提出来变成正数。如果不处理abs的话,那么所有选取方式的s之和就是0。原本是负的变成正的结果*2。
当然题目给的范围还是很人性化的(1 ≤ Taste scores of ingredients ≤ 10),这使我更坚定了用DP解题的信念。
#include <bits/stdc++.h>
#define ll long long
#define mod 10000000
using namespace std;
int x[1005];
ll dp[1005]; //dp[i]表示当前总和为i时的情况数
int main(){
int t;
cin>>t;
while(t--){
memset(dp,0,sizeof(dp));
int n;
cin>>n;
ll s=0;
for(int i=1;i<=n;++i){
cin>>x[i];
s+=x[i];
}
int g=s/2+s%2;
dp[0]=1;
for(int i=1;i<=n;++i){
for(int j=g;j>=0;--j){
if(j+x[i]>g)
continue;
dp[j+x[i]]+=dp[j];
}
}
ll ss=0;
for(int i=0;i<g;++i){
ss+=2*dp[i]*(s-i-i);
}
cout<<ss<<endl;
}
return 0;
}