codeforces B. Color the Fence 解题报告

题目链接:http://codeforces.com/problemset/problem/349/B

题目意思:给定v升的颜料和9个需要花费ad 升的颜料,花费ad 升的颜料意味着得到第d个数字,现在要求在所有的花费不超过v升的情况下,使得这些数字组合起来是最大的。

         一开始直接从最小花费的颜料着手,如果花费的颜料是相同的,就转到从d(也就是位数)最大贪心。这样测试9就开始卡住了。

         受到乌冬兄的指点迷津,终于有了思路,陆陆续续改了很多次,终于过了。以下摘自他的语录,白话文,大家请谅解:

      稳用颜料最少,最大的数字,先保证位数最长,然后再将剩余颜料从大数字开始贪心

      因为要数最大,所以根据“数”的比较顺序:
1。比较位数
2。从高位开始比较

     从数字比较的方法,推出贪心既思路

     由于本人悟性太低,下面是更详细的解说:

   1、先稳到用最小颜料既数字d,假设它价值为c
   2、先构造出s = v div c个d,求出剩余颜料r = v mod c
   3、从最高位扫描s,从大到小枚举可替换数字d' >= d,假设价值为c':若c'-c <= r,则替换当前位置的d为d', r -= c' - c
   4、最后得出替换后的s, s'即为所求
   注意:价值即一个数字要使用的颜料量

  

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 const int maxn = 1e6 + 5;
 9 struct paint
10 {  
11     int index;    // 数字
12     int num;      // 该数字所花费的颜料量
13 } a[maxn], b[maxn];
14 
15 int s[maxn];   // 用于保存结果
16 
17 int cmp(paint a, paint b)
18 {
19     if (a.num != b.num)    // 先保证用的颜料量最少
20         return a.num < b.num;
21     return a.index > b.index;   // 再保证数字最大
22 }
23 
24 int main()
25 {
26     int i, j, v, tmp, t1;
27     while (scanf("%d", &v) != EOF)
28     {
29 //        freopen("in.txt", "r", stdin);
30         for (i = 1; i <= 9; i++)
31         {
32             a[i].index = i;
33             scanf("%d", &a[i].num);
34             b[i].index = i;   //b用于保存未排序前的序列,以便下面从大数字开始枚举
35             b[i].num = a[i].num;
36         }
37         sort(a+1, a+10, cmp);
38         if (v < a[1].num)  // v比最少花费的颜料更少
39             printf("-1
");
40         else
41         { 
42             tmp = v / a[1].num;  // 得出最大位数
43             if (v % a[1].num == 0) // 如果刚好可以除尽,最大的数就是tmp个a[1].num的数。
44             {
45                 for (i = 0; i < tmp; i++)
46                     printf("%d", a[1].index);
47                 printf("
");
48             }
49             else
50             {
51                 for (i = 0; i < tmp; i++)
52                 {
53                     s[i] = a[1].index;  // 先得出目前来说最长的数字,但可能不是最终结果
54                 }
55                 int r = v % a[1].num;   // 余数
56                 t1 = r;
57                 for (i = 0; i < tmp; i++)
58                 {    
59                     for (j = 9; j >= 1; j--) // 从最大的位数开始枚举
60 { 61 if (b[j].num - a[1].num <= r && a[1].index < b[j].index) // 没有超过余数且数字比原来的排列数字的位数要大
62 { 63 s[i] = b[j].index; 64 r = r - (b[j].num - a[1].num); // 余数要有所减少
65 break; 66 } 67 } 68 } 69 if (t1 == r) // 如果根本没有可替换的数,那么就和刚好除尽的是同一种情况 70 { 71 for (i = 0; i < tmp; i++) 72 printf("%d", a[1].index); 73 printf(" "); 74 } 75 else 76 { 77 for (i = 0; i < tmp; i++) // 否则有替换的就输出新的最大数字
78 { 79 printf("%d", s[i]); 80 } 81 printf(" "); 82 } 83 } 84 } 85 } 86 return 0; 87 }
原文地址:https://www.cnblogs.com/windysai/p/3432414.html