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; }