题目链接:http://codeforces.com/problemset/problem/461/A
题目意思:给出一群由 n 个数组成的集合你,依次循环执行两种操作:
(1)每次Toastman得到一个集合,他计算所有数的和,并且将它加入到score里。之后他将这个集合传给Appleman。
(2)Appleman得到的集合如果只有一个数,就把它弃之,否则将这个集合分成 两个不相交且不空的集合,传回给Toastman.
这些操作不断执行直到集合个数变为0,也就是通过使集合都变成只有一个元素而一个个扔掉。问如何划分使得score最大。
其实通过模拟这两个操作可以发现应该怎样划分来使得score最大的。就是每次分成两个集合的时候,保证其中一个只含有单个元素的集合的那个元素是未划分前的集合那个是最小的。例如{1, 3, 8, 7} 第一次划分变成{1}, {3, 8, 7},第二次就是{3}, {8, 7}({1}这个集合根据题意已经扔掉了),第三次就是{7}, {8}。有没有发现,1 这个数被加了两次,3被加了三次,,7被加了四次,8也是被加了四次呢? 对!!这就是解题的规律所在。
我的做法是,边输入边统计整个集合的和,也就是最开始时那一群数要加到score中,然后从小到大排序,对于第 i 个数即a[i] 就乘上 i (循环初始是从1开始的),加入到score中,注意,对于最后那次划分,即只有两个数的那个集合{an-1, an},对于a[n],它不是乘上n次,而是n-1次。还有一个注意的地方是,score要用long long 。因为有可能 > 3e5*1e6,还蛮大的。
昨晚比赛的时候,由于A(读错题),B(被hack)题做得较差,做C题只剩20min,有一点点思路,来不及写完。得到的教训就是,注意数据范围,long long 处理之!!!
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <algorithm> 6 using namespace std; 7 8 typedef long long LL; 9 const int maxn = 3e5 + 5; 10 LL a[maxn]; 11 12 int main() 13 { 14 int n; 15 while (scanf("%d", &n) != EOF) 16 { 17 LL s = 0; 18 for (int i = 1; i <= n; i++) 19 { 20 scanf("%lld", &a[i]); 21 s += a[i]; 22 } 23 sort(a+1, a+1+n); 24 for (int i = 1; i < n; i++) 25 s += (LL) a[i] * (LL)i; // 因为之前算了一次总和,所以不是a[i]*(i+1) 26 s += (LL)(n-1)*(LL)a[n]; 27 printf("%lld ", s); 28 } 29 return 0; 30 }