【codechef】s=abs(这部分数-剩下的数),求所有选取方式的s之和

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


你可能感兴趣的:(【codechef】s=abs(这部分数-剩下的数),求所有选取方式的s之和)