• CodeForces Round #278 (Div.2) (待续)


    A

    这么简单的题直接贴代码好了。

     1 #include <cstdio>
     2 #include <cmath>
     3 using namespace std;
     4 
     5 bool islucky(int a)
     6 {
     7     a = abs(a);
     8     while(a)
     9     {
    10         if(a % 10 == 8) return true;
    11         a /= 10;
    12     }
    13     return false;
    14 }
    15 
    16 int main(void)
    17 {
    18     int a, b = 1;
    19     scanf("%d", &a);
    20     while(!islucky(a + b)) b++;
    21     printf("%d
    ", b);
    22     
    23     return 0;
    24 }
    代码君

    B

    题意:

    有4个从小到大排列的正整数,x1 x2 x3 x4 ,他们满足下面三个数相等:

    现在丢了4-n的数,只剩下其中的n个数(0≤n≤4)

    问能否找到4-n个正整数,使得这四个数重新满足上面的条件。

    分析:

    这道题思路很简单,就是比较繁琐,看到有人写了100多甚至200行代码,所以我还是觉得有必要把我的思路详细分析一下的。

    对条件变一下形,等价于下面两个条件:

    • x4 = 3x1
    • x1 + x4 = x2 + x3

    我们对n不同的情况来考虑

    • n=0,直接随便输出一组解就好了,比如 1 1 3 3
    • n=1,比如所给的数为a, a  a 3a 3a 就是一组解
    • n=2,所给的数为a b(a ≤ b), 我们断言b ≤ 3a时,才有解,为 a b (4a-b) 3a 。 首先若b ≤ 3a,前面所给的解是满足条件的。  若 b > 3a,则四个数中最小的一定是a,最大的一定是b,然而根据我们的条件有x4 = 3x1,即b = 3a,导出矛盾,所以无解。
    • n=3,设所给的三个数为a、b、c。我们只枚举有解的情况,其他情况则无解:  
      • 若c = 3a,则 a  b  (4a-b)  3a 是一组解
      • 若c ≤ 3a 且 b + c = 4a, 这时 a  b  c  3a 是一组解
      • 若c是3的倍数 且 a + b = ,  (c / 3)  a  b  c,是一组解
    • n=4直接判断是否满足题目要求条件就好了

    代码也比较短,只有50多行。

     1 #include <cstdio>
     2 #include <algorithm>
     3 using namespace std;
     4 
     5 int n, a[4], ans[4];
     6 
     7 bool solve()
     8 {
     9     switch(n)
    10     {
    11         case 0:
    12             ans[0] = ans[1] = 1, ans[2] = ans[3] = 3;
    13             return true;
    14         case 1:
    15             ans[0] = a[0], ans[1] = ans[2] = 3 * a[0];
    16             return true;
    17         case 2:
    18             if(a[1] <= a[0] * 3)
    19             {
    20                 ans[0] = a[0] * 3;
    21                 ans[1] = a[0] * 4 - a[1];
    22                 return true;
    23             }
    24             return false;
    25         case 3:
    26             if(a[2] == a[0] * 3)
    27                 { ans[0] = a[0] * 4 - a[1]; return true; }
    28             if(a[2] <= a[0] * 3 && a[1] + a[2] == a[0] * 4)
    29                 { ans[0] = a[0] * 3; return true; }
    30             if(a[2] % 3 == 0 && a[0] + a[1] == a[2]/3*4)
    31                 { ans[0] = a[2] / 3; return true; }
    32             break;
    33         case 4:
    34             if(a[0] + a[3] == a[1] + a[2] && a[0] * 3 == a[3])
    35                 return true;
    36     }
    37     return false;
    38 }
    39 
    40 int main(void)
    41 {
    42     scanf("%d", &n);
    43     for(int i = 0; i < n; ++i) scanf("%d", &a[i]);
    44     sort(a, a + n);
    45     if(solve())
    46     {
    47         printf("YES
    ");
    48         for(int i = 0; i < 4-n; ++i) printf("%d
    ", ans[i]);
    49     }
    50     else printf("NO
    ");
    51     
    52     return 0;
    53 }
    代码君

    C(暴力)

    题意:

    Master Yang 要去打败一个怪兽(Monster), 他和怪兽都有血量HP,攻击力ATK和防御力DEF。

    每个时刻,怪兽使杨大师血量减少 max{0, ATKM - DEFY}, 同样地, 杨大师对怪兽造成的伤害为 max{0, ATKY - DEFM}

    如果某一时刻HPY > 0 且 HPM ≤ 0,则视为将怪兽打败。

    为了能够打败怪兽,杨大师可以去商店购买HP、ATK和DEF。

    现给出杨大师和怪兽的HP、ATK和DEF,和购买每点HP、ATK和DEF所需要消耗的金币,求能够打败怪兽所需要的最少的金币。

    分析:

    因为数据范围很小,所以暴力是完全可以的。

    我们枚举可能购买的攻击力和防御力,然后算出打败怪兽后的剩余HP,如果HP少于1,那么就要购买相应的补回来。然后取每次总花费的最小值。

     1 #include <cstdio>
     2 #include <algorithm>
     3 using namespace std;
     4 
     5 int main(void)
     6 {
     7     int y[3], m[3], price[3], ans = 2000000000;
     8     for(int i = 0; i < 3; ++i) scanf("%d", &y[i]);
     9     for(int i = 0; i < 3; ++i) scanf("%d", &m[i]);
    10     for(int i = 0; i < 3; ++i) scanf("%d", &price[i]);
    11     
    12     for(int buyatk = 0; buyatk <= 200; ++buyatk)
    13         for(int buydef = 0; buydef <= 200; ++buydef)
    14         {
    15             int crtatk = y[1] + buyatk;
    16             int crtdef = y[2] + buydef;
    17             int hurty = max(0, m[1] - crtdef);        //杨大师收到的伤害
    18             int hurtm = max(0, crtatk - m[2]);    //怪兽收到的伤害
    19             if(hurtm == 0) continue;    //打不掉怪兽的血,跳过循环
    20             int k = m[0] % hurtm == 0 ? m[0]/hurtm : m[0]/hurtm + 1;
    21             int LeftHP = y[0] - hurty * k;
    22             int cost = price[1] * buyatk + price[2] * buydef + (1 - LeftHP > 0 ? (1 - LeftHP) * price[0] : 0);
    23             ans = min(ans, cost);
    24         }
    25     
    26     printf("%d
    ", ans);
    27     
    28     return 0;
    29 }
    代码君

    D

    像这种贪心贪不出来的都感觉是DP。

    在CF上扒了一个46ms的代码,也总算是看懂了。

    题意:

    纸条上有n个数,可以将纸条剪为若干小段(只有一个数字也可以),使得每段上的数字满足:

    • 最大值与最小值之差不超过s
    • 数字个数不少于l

    分析:

    从第一个数开始向左右两个方向延伸(第一个数只能往右延伸),求得一个最大的闭区间[left1, right1],使得这个区间里的数都满足第一个条件 max - min ≤ s.

    如果区间的长度小于l,则无解

    如果长度大于等于l,我们则求出了第一段纸片右端点的一个范围[l, right1]

    第二段纸片从第 right + 1 个数向两侧延伸,这时向左延伸就有了一个界限,因为要保证第一段纸片至少有l个数,所以第二段纸片最多只能向左延伸到第l+1个数。

    记此时的区间为[left2, right2],同样地,看区间的长度是否≥l来判断是否有解。这样一来,为了保证在第三段纸片延伸的时候第二段至少有l个数,所以第三段纸片至多向左延伸到left2+l+1

    所以我们用last来记录每次向左延伸的界限

     1 #include <cstdio>
     2 #include <algorithm>
     3 using namespace std;
     4 
     5 const int maxn = 100000 + 10;
     6 long long a[maxn], last = 0;
     7 bool flag = true;
     8 
     9 int main(void)
    10 {
    11     //freopen("Din.txt", "r", stdin);
    12     
    13     long long n, s, l, ans = 0;
    14     scanf("%I64d%I64d%I64d", &n, &s, &l);
    15     for(int i = 0; i < n; ++i) scanf("%I64d", &a[i]);
    16     
    17     long long pos, left, right;
    18     for(pos = 0; pos < n; ++pos)    //从pos位置开始延伸
    19     {
    20         long long maxm, minm, cnt = 1;    //区间延伸过程中的最小值和最大值以及区间中元素的个数
    21         
    22         maxm = a[pos], minm = a[pos];  
    23         right = pos + 1;
    24         while(right < n)
    25         {
    26             maxm = max(maxm, a[right]);
    27             minm = min(minm, a[right]);
    28             if(maxm - minm <= s) cnt++;
    29             else break;
    30             right++;
    31         }
    32         right--;
    33         
    34         //maxm = a[pos], minm = a[pos];
    35         left = pos - 1;
    36         while(left >= last)
    37         {
    38             maxm = max(maxm, a[left]);
    39             minm = min(minm, a[left]);
    40             if(maxm - minm <= s) cnt++;
    41             else break;
    42             left--;
    43         }
    44         left++;
    45         
    46         if(cnt < l)
    47         {
    48             flag  =false;
    49             break;
    50         }
    51         ans++;
    52         last = left + l;
    53         pos = right;
    54     }
    55     
    56     if(!flag) ans = -1;
    57     printf("%I64d
    ", ans);
    58     
    59     return 0;
    60 }
    代码君

    E(数论+构造)

    题意:

    给出一个正整数n,问是否存在一个 1~n的排列,使得前i个数的乘积模上n的余数得到的序列是0~n-1的一个排列。

    分析:

    当n为1、4和素数的时候有解,构造方法是用 (i+1)*(i的逆元)%n 填充当前的数。

    这道题先留着,等我比较系统地学习数论以后在给出严格证明以及代码。

  • 相关阅读:
    SpringMVC-11-文件上传和下载
    SpringMVC-10-拦截器Interceptor
    SpringMVC-09-Ajax技术
    SpringMVC-08-整合SSM之CRUD
    SpringMVC-08-SpringMVC层编写
    SpringMVC-08-整合SSM之Spring层编写
    SpringMVC-08-Mybatis层编写
    SpringMVC-08-整合SSM之基本环境搭建
    SpringMVC-07-JSON讲解
    SpringMVC-06-数据处理
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/4116052.html
Copyright © 2020-2023  润新知