Naughty Stone Piles

题目:http://codeforces.com/problemset/problem/227/D

题意:n堆个数石子,每堆石子有ai个,通过合并(即将一堆石子移到另一堆石子上),将所有石子合并为一堆,每次合并的代价是这堆石子的个数,在ki的限制下,每堆石子最多只能被合并k次,k次之后就必须移动该堆石子到别的堆上,求合并到最后的总的最小代价。

题解:emmmmm,既然是找最小代价,那么石子个数最多的那堆石子肯定是不移动的,把个数次小的k堆石子移动到这堆石子上,所以这k堆石子移动了一次,这k堆石子中的每一个又是比他们小的k堆石子合并到它们身上的,即这k*k堆移动了两次,以此类推:

k                 1次

k*k              2次

k*k*k           3次

k*k*k*k        4次

         .

         .       

         .

         .

所以总代价最小即是k*1*个数+k^2*2*个数+k^3*3*个数.....

当然k为1时需要特判,最小堆移动了n-1次,次小堆移动n-2次,最大堆不动,具体看代码。

注意大部分数据都是long long 范围。

 1 #include <map>
 2 #include <stack>
 3 #include <queue>
 4 #include <cmath>
 5 #include <string>
 6 #include <limits>
 7 #include <cstdio>
 8 #include <vector>
 9 #include <cstdlib>
10 #include <cstring>
11 #include <iostream>
12 #include <algorithm>
13 #define Scc(c) scanf("%c",&c)
14 #define Scs(s) scanf("%s",s)
15 #define Sci(x) scanf("%d",&x)
16 #define Sci2(x, y) scanf("%d%d",&x,&y)
17 #define Sci3(x, y, z) scanf("%d%d%d",&x,&y,&z)
18 #define Scl(x) scanf("%I64d",&x)
19 #define Scl2(x, y) scanf("%I64d%I64d",&x,&y)
20 #define Scl3(x, y, z) scanf("%I64d%I64d%I64d",&x,&y,&z)
21 #define Pri(x) printf("%d
",x)
22 #define Prl(x) printf("%I64d
",x)
23 #define Prc(c) printf("%c
",c)
24 #define Prs(s) printf("%s
",s)
25 #define For(i,x,y) for(int i=x;i<y;i++)
26 #define For_(i,x,y) for(int i=x;i<=y;i++)
27 #define FFor(i,x,y) for(int i=x;i>y;i--)
28 #define FFor_(i,x,y) for(int i=x;i>=y;i--)
29 #define Mem(f, x) memset(f,x,sizeof(f))
30 #define LL long long
31 #define ULL unsigned long long
32 #define MAXSIZE 100005
33 #define INF 0x3f3f3f3f
34 const int mod=1e9+7;
35 const double PI = acos(-1.0);
36 
37 using namespace std;
38 int cmp(LL a,LL b)
39 {
40     return a<b;
41 }
42 int main()
43 {
44 
45     LL n;
46     Scl(n);
47     int i;
48     LL a[MAXSIZE]= {0};
49     for (i=1; i<=n; i++)
50         Scl(a[i]);
51     sort(a+1,a+1+n);
52     LL  tmp=0;
53     For_(i,1,n-1)//注意这两个for循环的先后顺序
54     tmp+=a[i]*(n-i);
55     For_(i,1,n)
56     a[i]+=a[i-1];//用来计算每隔k的x次方堆石子被合并的次数是相同的,即(a[m]-a[m-k])*cnt,
57     int q;
58     Sci(q);
59     while(q--)
60     {
61         LL ans=0;
62         LL k;
63         Scl(k);
64         int t=k;
65         LL cnt=1,m=n-1;
66         if(k!=1)
67         {
68             while(m>=k)//当k大于等于n时,不执行,直接执行 ans+=cnt*a[m];,即最小代价是前n-1堆石子个数和,即1*a[m].
69             {
70                 ans+=(a[m]-a[m-k])*cnt;
71                 cnt++;
72                 m-=k;
73                 k=k*t;//k的变化是k k^2 k^3 k^4...每次乘以最初的k的大小,刚开始写成k*=k,wa一下午,我太难了QAQ
74             }
75             ans+=cnt*a[m];
76         }
77         else
78             ans=tmp;
79         printf("%I64d ",ans);//还有这个谜之输出。
80     }
81     return 0;
82 }
View Code

 嗯,本来不是难题,硬是用了我一天的时间,真是。。。。。。多个地方都有出过问题。唉。

原文地址:https://www.cnblogs.com/hbhdhd/p/11413957.html