• #635 div2 A


    参考资料:http://codeforces.com/blog/entry/76099

    A. Ichihime and Triangle

      $Description:$

        给你四个整数 $a, b, c, d$, 选择三个数$x, y, z$构成一个三角形,其中$aleq xleq b, bleq yleq c, cleq zleq d$.

      打印任何一组符合条件的$x, y, z$即可。

      $Solve:$

        构成三角形则需要满足任意两边之和大于第三边,那么我们令$x = b, y = c, z = c$就一定符合条件。

      $Code:$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int main()
     5 {
     6     int t; cin >> t;
     7     while(t --)
     8     {
     9         int a, b, c, d;
    10         cin >> a >> b >> c >> d;
    11         printf("%d %d %d
    ", b, c, c);
    12     }
    13     return 0;
    14 }
    View Code

     B. Kana and Dragon Quest game

       $Description:$

        怪兽的血量为$x$,你有两种攻击方式:

        $1:x = left lfloor x / 2 ight floor + 10$

        $2:x = x - 10$

        第一种可以使用$n$次,第二种可以使用$m$次,请问你是否可以消灭怪兽$(x <= 0)$。

      $Solve:$

        直接使用$n$次第一种攻击来使怪兽血量大幅下降,然后判断使用$m$次第二种攻击是否可以消灭怪兽。

        有一种特殊情况是初始值$x leq 10 $ $ And $ $ m = 1$,这种情况使用上面的方案就不能成功,但可以直接使用$m$次攻击,所以我们需要特判一下。

      $Code:$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int main()
     5 {
     6     int t; cin >> t;
     7     while(t --)
     8     {
     9         int x, n, m;
    10         cin >> x >> n >> m;
    11         if(m * 10 >= x) { puts("Yes"); }
    12         else
    13         {
    14             for(int i = 1; i <= n; i ++)
    15                 x = x / 2 + 10;
    16             if(m * 10 >= x) puts("Yes");
    17             else puts("No");
    18         }
    19     }
    20     return 0;
    21 }
    View Code

    C. Linova and Kingdom

      $Description:$

        给你一颗树,$1$为根,选择$k$个结点使其权值为$0$,其他结点的权值为$1$,这$k$个点都往根节点走,每经过一个点,加上他的权值,所获得的权值和为这个点的幸福度,最后求$k$个点的幸福度之和最大可以是多少?

      $Solve:$

        首先很容易知道的是,选择了一个结点$a$,那么以$a$为根的子树也一定选择了,否则我们就会浪费掉未选择的(因为$a$走不到那个结点,所以浪费了他的权值)。

        于是我们可以计算出每个点的幸福度,然后排序,取前$k$大求和即是答案。

        举例来计算某个点的幸福度:

                    

        计算$6$的权值,即我们选择了$6$号点,那么他的子树也一定选择了,由于在计算他的子节点时,$6$还没有被选择,所以他们加上了$6$的权值,即多加了$cnt[6](cnt[6]是6子节点个数)$,所以我们需要减去$cnt[6]$,再加上$d[6](d[6]是6到根节点的距离)$,因为此时$6$之上的结点还没有被选择,所以他们的权值都是$1$。

       $Code:$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 2e5 + 10, M = N << 1;
     4 typedef long long ll;
     5 
     6 int n, k;
     7 int h[N], e[M], ne[M];
     8 int tot = 0;
     9 
    10 
    11 ll d[N], cnt[N], val[N];
    12 
    13 void add(int a, int b)
    14 {
    15     e[ ++ tot] = b; ne[tot] = h[a]; h[a] = tot;
    16 }
    17 
    18 int dfs(int p, int fa, int st)
    19 {   
    20     d[p] = st;
    21     int res = 1;
    22     for(int i = h[p]; i; i = ne[i])
    23     {
    24         int j = e[i];
    25         if(j == fa) continue;
    26         res += dfs(j, p, st + 1);
    27     }
    28     cnt[p] = res;
    29     return res;
    30 }
    31 
    32 int main()
    33 {
    34     cin >> n >> k;
    35     for(int i = 1; i < n; i ++)
    36     {
    37         int a, b; scanf("%d %d", &a, &b);
    38         add(a, b); add(b, a);
    39     }
    40     dfs(1, -1, 0);
    41     for(int i = 1; i <= n; i ++) val[i] = d[i] - cnt[i] + 1;
    42     sort(val + 1, val + n + 1, greater<int>());
    43     ll ans = 0;
    44     for(int i = 1; i <= k; i ++) ans += val[i];
    45     cout << ans << endl;
    46     return 0;
    47 }
    View Code

    D. Xenia and Colorful Gems

       $Description:$

        你有三个正整数集合,从三个集合中分别选出一个数为$x, y, z$, 使得$(x - y)^2 + (x - z)^2 + (y - z) ^ 2$最小是多少。

      $Solve:$

        显然对于选出来的三个数一定存在以下大小关系的:

        $xleq yleq z$, $xleq zleq y$,$yleq xleq z$,$yleq zleq x$,$zleq xleq y$,$zleq yleq x$

        那么我们可以枚举中间的数,再用二分分别算出小于等于自己的最大数和大于等于自己的最小数,再利用公式得出结果,在所有的结果中取最小值即可。

      $Code:$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 1e5 + 10;
     4 const long long INF = 3e18 + 10;
     5 typedef long long ll;
     6 
     7 ll r[N], g[N], b[N];
     8 ll ans = INF;
     9 
    10 void read(int n, ll *a)
    11 {
    12     for(int i = 1; i <= n; i ++)   
    13         scanf("%lld", &a[i]);
    14 }
    15 
    16 ll cal(ll x, ll y, ll z)
    17 {
    18     return (x - y) * (x - y) + (x - z) * (x - z) + (y - z) * (y - z);
    19 }
    20 
    21 ll findLess(ll *a, int na, ll x)
    22 {
    23     int l = 1, r = na;
    24     ll res = -1;
    25     while(l <= r)
    26     {
    27         int m = l + r >> 1;
    28         if(a[m] <= x)
    29         {
    30             l = m + 1;
    31             res = a[m];
    32         }  
    33         else r = m - 1;
    34     }
    35     return res;
    36 }
    37 
    38 ll findMore(ll *a, int na, ll x)
    39 {
    40     int l = 1, r = na;
    41     ll res = -1;
    42     while(l <= r)
    43     {
    44         int m = l + r >> 1;
    45         if(a[m] >= x)
    46         {
    47             r = m - 1;
    48             res = a[m];
    49         }
    50         else l = m + 1;
    51     }
    52     return res;
    53 }
    54 
    55 void solve(ll *a, ll *b, ll *c, int na, int nb, int nc)
    56 {
    57     for(int i = 1; i <= na; i ++)
    58     {
    59         ll x = a[i];
    60         ll y = findLess(b, nb, x);
    61         ll z = findMore(c, nc, x);
    62         if(y == -1 || z == -1) continue;
    63         ans = min(ans, cal(x, y, z));
    64     }
    65 }
    66 
    67 int main()
    68 {
    69     int t; cin >> t;
    70     while(t --)
    71     {
    72         ans = INF;
    73         int nr, ng, nb;
    74         scanf("%d%d%d", &nr, &ng, &nb);
    75         read(nr, r); read(ng, g); read(nb, b);
    76         sort(r + 1, r + nr + 1);
    77         sort(g + 1, g + ng + 1);
    78         sort(b + 1, b + nb + 1);
    79         solve(r, b, g, nr, nb, ng); 
    80         solve(r, g, b, nr, ng, nb);
    81         solve(b, r, g, nb, nr, ng);
    82         solve(b, g, r, nb, ng, nr);
    83         solve(g, r, b, ng, nr, nb);
    84         solve(g, b, r, ng, nb, nr);
    85         cout << ans << endl;
    86     }
    87     return 0;
    88 }
    View Code

    E. Kaavi and Magic Spell

        $Description:$

        给你两个字符串$S,T和一个空串A$,每次从$S$的头部拿出一个字符串可以放入$A$的头部和尾部,那么在这个过程中有多少情况下$T$是$A$的一个前缀。

      $Solve:$

        区间DP

        设$f[i][j]为T[i]-T[j]构成的字符串是A的前缀的方案数$

        枚举$S$,与一般的区间DP不同的是,$S_i即代表了区间的长度为i$,所以我们可以少一维循环。

        状态转移:

          $f[l][r] = f[l][r] + f[l + 1][r](S[i] = T[l])$

          $f[l][r] = f[l][r] + f[l][r - 1](S[i] = T[r])$

          由于是前缀且$lenT leq lenS$,所以在长度超过$lenT$之后,同样满足上述方程。

      $Code:$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 3010, mod = 998244353;
     4 
     5 char s[N], t[N];
     6 int f[N][N];
     7 
     8 int main()
     9 {
    10     scanf("%s %s", s + 1, t + 1);
    11     int n = strlen(s + 1);
    12     int m = strlen(t + 1);
    13 
    14     for(int i = 1; i <= n + 1; i ++)
    15         f[i][i - 1] = 1;
    16 
    17     for(int i = 1; i <= n; i ++)
    18     {
    19         for(int l = 1; l + i - 1 <= n; l ++)
    20         {
    21             int r = l + i - 1;
    22             if(s[i] == t[l] || l > m)
    23                 f[l][r] = (f[l][r] + f[l + 1][r]) % mod;
    24             if(s[i] == t[r] || r > m)
    25                 f[l][r] = (f[l][r] + f[l][r - 1]) % mod;
    26         }
    27     }
    28 
    29     int ans = 0;
    30     for(int i = m; i <= n; i ++)
    31         ans = (ans + f[1][i]) % mod;
    32     cout << ans << endl;
    33 
    34     return 0;
    35 }
    View Code

    F. Yui and Mahjong Set

      $Description:$

        交互式问题

        有一个整数集合,范围为:$[0, n]$,对于某个数而言,个数最少$0$个,最多是$n$个,我们的目标就是求出$[0,n]$中每个数的个数。

        已知$T:$三元组个数(元组的数相同)例:$(1, 1, 1)$

          $S:$三元组个数(元组的数依次递增)例:$(2, 3, 4)$

          其中对于集合$(1, 1, 1, 1, 2, 3)$

            $T = 4$, $S = 4$

        我们每次向集合中插入一个$[0, n]$的数,程序会反馈$T和S$给我们(已知初始集合的$T和S$)。

        可以插入$n$个数

      $Solve:$

        插入顺序:$n-1,n-2,n-3......5,4,3,1,2,1$

        按照这样的插入顺序我们可以轻易的求出$[1,4]$的个数,然后按顺序从小到大依次求出其他数。

        显然我们是离线处理的

        由于插入了两次$1$,所以可以简单的求出$1$的个数:

          对于某一个数来说:$T = C_{n}^{3}$

          插入这个数之后:$T = C_{n+1}^{3}$

          相减即 $frac{n imes (n - 1)}{2} = riangle T$

        对于其他数来说,要通过$S$来求:

          举例连续的五个数:$1, 2, 3, 4, 5$,个数分别为:$a, b, c, d, e$

          我们插入$3$,显然$ riangle S = a imes b + b imes d + d imes e$

          根据已经求出来的数来算未知的数即可。

      $Code:$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 110;
     4 
     5 int n;
     6 int t0, s0;
     7 int t[N], s[N], ans[N];
     8 
     9 void ask(int x, int &a, int &b)
    10 {
    11     printf("+ %d
    ", x);
    12     fflush(stdout);
    13     scanf("%d %d", &a, &b);
    14     a -= t0, b -= s0;
    15     t0 += a, s0 += b;
    16 }
    17 
    18 int cal(int x)
    19 {
    20     for(int i = 1; ; i ++)
    21         if(i * (i - 1) == 2 * x)
    22             return i;
    23 }
    24 
    25 int main()
    26 {
    27     scanf("%d%d%d", &n, &t0, &s0);
    28     for(int i = n - 1; i >= 3; i --) ask(i, t[i], s[i]);
    29     int a, b;
    30     ask(1, t[1], s[1]); ask(2, t[2], s[2]); ask(1, a, b);
    31     ans[1] = cal(a) - 1;
    32     ans[3] = b - s[1] - 1;
    33     ans[2] = s[1] / (ans[3] + 1);
    34     ans[4] = s[2] / (ans[3] + 1) - ans[1] - 2;
    35     for(int i = 5; i <= n; i ++)
    36         ans[i] = (s[i - 2] - ans[i - 4] * ans[i - 3] - ans[i - 3] * (ans[i - 1] + 1)) / (ans[i - 1] + 1) - 1;
    37     printf("!");
    38     ans[n] ++;
    39     for(int i = 1; i <= n; i ++) printf(" %d", ans[i]);
    40     return 0;
    41 }
    View Code
  • 相关阅读:
    Filter 和 interceptor 的区别
    JAVA基础知识|Optional
    CentOS 7安装MariaDB 10详解以及相关配置
    Linux系统zookeeper环境搭建(单机、伪分布式、分布式)
    Java设计模式——模板方法模式
    Java设计模式——装饰模式
    Java设计模式——观察者模式
    Java设计模式——代理模式
    Java设计模式——适配器模式
    Java设计模式——策略模式
  • 原文地址:https://www.cnblogs.com/nonameless/p/12816913.html
Copyright © 2020-2023  润新知