bzoj1538 [NWERC2017]High Score
网上的题解都很奇怪。。
经过相当长时间的思考,有了一个有效(自认为)的解法
设某一种合法分配方案完成后三个数分别变为a,b,c,其中a>=c,b>=c
此时如果让c减1,让a或b加1(设让t加了1),那么答案增加的值为2t+1-2c+1-7=2t-2c-5
令其>0,则t-c>2.5
由于t,c是整数,因此t-c>=3
也就是说,如果这种方案中最大值-最小值>=3,且最小值还能变得更小,那么一定存在一种更优方案(就是让c减1,让最大数加1后得到的方案),也就是说它一定不是最优方案
那么只需要考虑两种可能的最优方案:
1.最小值不能变得更小了;此时显然最优方案是把d全部加到三个数中最大数上
2.最大值-最小值<3;此时只要枚举最大值-最小值和次大值-最小值,然后O(1)求出答案的3个数并验证即可
A掉了。。。
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 //#include<cassert> 6 using namespace std; 7 #define fi first 8 #define se second 9 #define mp make_pair 10 #define pb push_back 11 typedef long long ll; 12 typedef unsigned long long ull; 13 typedef pair<int,int> pii; 14 ll calc(ll a,ll b,ll c) 15 { 16 return a*a+b*b+c*c+7*min(a,min(b,c)); 17 } 18 vector<ll> p,q; 19 ll solve(ll a,ll b,ll c,ll d) 20 { 21 ll i,j,s=c+a+b+d,an=-0x3f3f3f3f; 22 q.clear();q.pb(a);q.pb(b);q.pb(c); 23 sort(q.begin(),q.end()); 24 for(i=0;i<=2;i++) 25 { 26 for(j=0;j<=2;j++) 27 { 28 if(s-i-j>=0&&(s-i-j)%3==0) 29 { 30 p.clear(); 31 p.pb((s-i-j)/3); 32 p.pb(p[0]+i);p.pb(p[0]+j); 33 sort(p.begin(),p.end()); 34 if(p[0]>=q[0]&&p[1]>=q[1]&&p[2]>=q[2]) 35 { 36 an=max(an,calc(p[0],p[1],p[2])); 37 } 38 } 39 } 40 } 41 return an; 42 } 43 ll T,a,b,c,d; 44 int main() 45 { 46 //freopen("/tmp/1538/1.in","r",stdin); 47 //freopen("/tmp/1538/1.ans","w",stdout); 48 scanf("%lld",&T);//assert(3<=T&&T<=7); 49 while(T--) 50 { 51 scanf("%lld%lld%lld%lld",&a,&b,&c,&d); 52 p.clear();p.pb(a);p.pb(b);p.pb(c); 53 sort(p.begin(),p.end()); 54 ll a1=calc(p[0],p[1],p[2]+d); 55 printf("%lld\n",max(a1,solve(a,b,c,d))); 56 } 57 return 0; 58 }