zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 54 (Rated for Div. 2) Solution

    A - Minimizing the String

    solved

    题意:给出一个字符串,可以移掉最多一个字符,在所有可能性中选取一个字典序最小的。

    思路:显然,一定可以移掉一个字符,如果移掉的字符的后一个字符大于当前字符,那么字典序会变大。

    那只需要从左往右,遇到第一个后面的字符大于当前字符的就可以移掉该字符。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define N 200010
     5 int n;
     6 char s[N];
     7 
     8 int main()
     9 {
    10     while (scanf("%d%s", &n, s + 1) != EOF)
    11     {
    12         int pos = n;
    13         for (int i = 1; i < n; ++i) if (s[i + 1] < s[i])
    14         {
    15             pos = i;
    16             break;  
    17         }
    18         s[pos] = 0;
    19         printf("%s", s + 1);
    20         printf("%s
    ", s + pos + 1);
    21     }
    22     return 0;
    23 }
    View Code

    B - Divisor Subtraction

    solved

    题意:给出一个数n,如果n = 0,那么程序就结束。否则减去这个数的最小质因子,再循环执行该算法,问程序会执行多少步。

    思路:

    我们假设数$n的最小质因子为x, 令 y = frac{n}{x}$

    如果$y$是偶数,那么答案就很明显,直接不断减去2

    如果$y是奇数,那么我们先减去一个x, 那么就会变成 n = (y - 1) cdot x$

    $此时 (y - 1) 显然为偶数 就不断减去2就可以$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 ll x;
     6 
     7 ll find(ll x)
     8 {
     9     ll limit = sqrt(x + 1); 
    10     for (ll i = 2; i <= limit; ++i) if (x % i == 0) return i; 
    11     return x;
    12 }
    13 
    14 int main()
    15 {
    16     while (scanf("%lld", &x) != EOF)
    17     {
    18         ll y = find(x); ll z = x / y;
    19         printf("%lld
    ", (z - 1) * y / 2 + 1);    
    20     }
    21     return 0;
    22 }
    View Code

    C - Meme Problem

    solved

    题意:给出一个$d, 找a + b = d and a cdot b = d$

    思路:将$a = d - b$ 代入第二个式子,解二元一次方程。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int t, d;
     5 
     6 int main()
     7 {
     8     scanf("%d", &t);
     9     while (t--)
    10     {
    11         scanf("%d", &d);
    12         if (d * d < 4 * d) puts("N");
    13         else
    14         {
    15             double delta = sqrt(d * d - 4 * d);
    16             double b = (d - delta) / 2;
    17             double a = d - b;
    18             printf("Y %.10f %.10f
    ", a, b);
    19         }
    20     }
    21     return 0;
    22 }
    View Code

    D - Edge Deletion

    Upsolved

    题意:给出一个无向图,定义$d_i为 1 - i 的最短路径$,定义一个点为好点为1 - 这个点的最短路径为 $d_i$,最多保留k条边,使得剩下的点中好点最多。

    思路:Dijkstra构造最短路树,对最短路树DFS或者BFS皆可,按这个搜索顺序选取边,显然每选取一条边都会增加一个好点,所以最后好点的数量显然为$min(k + 1, n)$

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 #define ll long long
      5 #define INFLL 0x3f3f3f3f3f3f3f3f
      6 #define N 300010
      7 int n, m, k;
      8 
      9 struct Edge
     10 {
     11     int u, v; ll w; 
     12     Edge() {}
     13     Edge(int u, int v, ll w) : u(u), v(v), w(w) {}  
     14 }edge[N]; 
     15 
     16 struct graph
     17 {
     18     struct node
     19     {
     20         int to, nx, id; ll w;
     21         node () {}
     22         node (int to, int nx, int id, ll w) : to(to), nx(nx), id(id), w(w) {}
     23     }a[N << 1];
     24     int head[N], pos;
     25     void init() { memset(head, 0, sizeof head); pos = 0; } 
     26     void add(int u, int v, int id, ll w)
     27     {
     28         a[++pos] = node(v, head[u], id, w); head[u] = pos;
     29         a[++pos] = node(u, head[v], id, w); head[v] = pos;
     30     }
     31 }G, g;  
     32 #define erp(G, u) for (int it = G.head[u], v = G.a[it].to, w = G.a[it].w; it; it = G.a[it].nx, v = G.a[it].to, w = G.a[it].w)
     33 
     34 struct Dijkstra
     35 {
     36     struct node
     37     {
     38         int to; ll w;
     39         node () {}
     40         node (int to, ll w) : to(to), w(w) {}
     41         bool operator < (const node &r) const { return w > r.w; } 
     42     };
     43     struct DIST 
     44     {
     45         ll w; int id;
     46         DIST() {}
     47         DIST(ll w, int id) : w(w), id(id) {}
     48     }dist[N]; bool used[N]; 
     49     void solve() 
     50     {
     51         for (int i = 1; i <= n; ++i)
     52         {
     53             dist[i] = DIST(INFLL, -1); 
     54             used[i] = false; 
     55         }
     56         dist[1] = DIST(0, -1); 
     57         priority_queue <node> q; q.emplace(1, 0);
     58         while (!q.empty())
     59         {
     60             int u = q.top().to; q.pop();
     61             if (used[u]) continue;
     62             used[u] = 1; 
     63             int id = dist[u].id; if (id != -1) g.add(edge[id].u, edge[id].v, id, edge[id].w); 
     64             erp(G, u) if (!used[v] && dist[v].w > dist[u].w + w) 
     65             {
     66                 dist[v].w = dist[u].w + w; 
     67                 dist[v].id = G.a[it].id;
     68                 q.emplace(v, dist[v].w);
     69             }
     70         }
     71     }
     72 }dij;
     73 
     74 vector <int> res;
     75 void DFS(int u, int fa)
     76 {
     77     erp(g, u) if (v != fa && res.size() < k)
     78     {
     79         res.push_back(g.a[it].id); 
     80         DFS(v, u);
     81     }
     82 }
     83 
     84 int main()
     85 {
     86     while (scanf("%d%d%d", &n, &m, &k) != EOF)
     87     {
     88         G.init(); g.init(); res.clear();
     89         for (int i = 1, u, v, w; i <= m; ++i)
     90         {
     91             scanf("%d%d%d", &u, &v, &w);
     92             edge[i] = Edge(u, v, w);
     93             G.add(u, v, i, w);
     94         } dij.solve(); DFS(1, 1); 
     95         int len = res.size(); 
     96         printf("%d
    ", len);
     97         for (int i = 0; i < len; ++i) printf("%d%c", res[i], " 
    "[i == len - 1]);
     98     }
     99     return 0;
    100 }
    View Code

    E - Vasya and a Tree

    solved

    题意:给出一棵树,有m次操作,每次将以x为根的子树下,和x的距离不超过d的所有点的权值都加上v,最后输出每个点的权值。

    思路:首先考虑$d$特别大的情况下,也就是子树下所有点都要加上,那么更新的时候直接在那个点上更新,

    最后只需要DFS一遍,每个点都加上父亲的权值即可。

    再考虑加入限制的情况:

    其实对于一个点,我们DFS下去的时候,到回溯上来这段时间,遍历的都是它的子树,那么我们可以设立一个标记

    对于每个点,给他加上更新的权值的时候,我们在对应的子树的deep界限那里加上,那么每次遍历下去的时候,首先要减去这个当前深度对应的lazy值,然后再更新答案,回溯上来的时候取消标记即可。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 300010
     6 #define pii pair <int, int>
     7 int n, m;
     8 vector <int> G[N]; 
     9 vector <pii> vec[N];
    10 ll ans[N], gap[N];
    11 
    12 int deep[N], fa[N];
    13 void DFS(int u, ll res)
    14 {
    15     res -= gap[deep[u]];
    16     for (auto it : vec[u]) 
    17     {
    18         int dep = min(deep[u] + it.first + 1, n + 1);
    19         gap[dep] += it.second;  
    20         res += it.second;
    21     }
    22     ans[u] = res;
    23     for (auto v : G[u]) if (v != fa[u])
    24     {
    25         fa[v] = u;
    26         deep[v] = deep[u] + 1;
    27         DFS(v, res); 
    28     }
    29     for (auto it : vec[u])
    30     {
    31         int dep = min(deep[u] + it.first + 1, n + 1);
    32         gap[dep] -= it.second;
    33         res -= it.second;
    34     }
    35     res += gap[deep[u]];
    36 }
    37     
    38 void init()
    39 {
    40     for (int i = 1; i <= n; ++i)
    41     {
    42         G[i].clear();
    43         vec[i].clear();
    44     }
    45     memset(gap, 0, sizeof gap);
    46     deep[1] = 0; 
    47 }
    48 
    49 int main()
    50 {
    51     while (scanf("%d", &n) != EOF)
    52     {
    53         init(); 
    54         for (int i = 1, u, v; i < n; ++i)
    55         {
    56             scanf("%d%d", &u, &v);
    57             G[u].push_back(v);
    58             G[v].push_back(u);
    59         }
    60         scanf("%d", &m);
    61         for (int i = 1, x, d, v; i <= m; ++i)
    62         {
    63             scanf("%d%d%d", &x, &d, &v);
    64             vec[x].emplace_back(min(d, n), v); 
    65         }
    66         DFS(1, 0);
    67         for (int i = 1; i <= n; ++i) printf("%lld%c", ans[i], " 
    "[i == n]);
    68     }
    69     return 0; 
    70 }
    View Code

    F. Summer Practice Report

     Upsolved.

    题意:

    $第i天有x_i个糖果,y_i个果冻,要求将他们放在一排,且相同的东西连续最多放k个,要放n天,求是否有放置方案满足$

    思路:

    $dp[i][1/0] 表示第i天最后一部分放糖果还是果冻的最小数量,然后枚举四种状态DP转移即可。$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define INF 0x3f3f3f3f
     6 #define N 300010
     7 int n, k, x[N], y[N], dp[N][2]; 
     8 
     9 int calc(int pa, int pb, int a, int b)
    10 {
    11     int ans = INF;
    12     if (pa <= k)
    13     {
    14         int tot = pa + a;
    15         int cnt = (tot + k - 1) / k - 1;
    16         if (b == cnt) ans = min(ans, tot - cnt * k);    
    17         else if (b > cnt && b <= (ll)a * k) ans = min(ans, 1);
    18     }
    19     if (pb <= k)
    20     {
    21         int cnt = (a + k - 1) / k - 1;
    22         if (b == cnt) ans = min(ans, a - cnt * k);
    23         else if (b > cnt && b <= (ll)a * k - pb) ans = min(ans, 1);
    24     }
    25     return ans;
    26 }    
    27 
    28 bool solve()
    29 {
    30     memset(dp, 0x3f, sizeof dp); dp[0][0] = dp[0][1] = 0;
    31     for (int i = 1; i <= n; ++i)
    32     {
    33         dp[i][0] = calc(dp[i - 1][0], dp[i - 1][1], x[i], y[i]);
    34         dp[i][1] = calc(dp[i - 1][1], dp[i - 1][0], y[i], x[i]);
    35         if (dp[i][0] == INF && dp[i][1] == INF) return false;
    36     }
    37     return true;
    38 }
    39 
    40 int main()
    41 {
    42     while (scanf("%d%d", &n, &k) != EOF)
    43     {
    44         for (int i = 1; i <= n; ++i) scanf("%d", x + i);
    45         for (int i = 1; i <= n; ++i) scanf("%d", y + i);
    46         puts(solve() ? "YES" : "NO");
    47     }
    48     return 0;
    49 }
    View Code

    G. Array Game

    Unsolved.

  • 相关阅读:
    POJ 题目1145/UVA题目112 Tree Summing(二叉树遍历)
    车牌号
    小程序开发 标题新闻
    小程序开发 轮播
    小程序开发
    App phonegap
    Jquery Cookie操作
    App 添加权限
    App WebView实例化
    Vue 组件化
  • 原文地址:https://www.cnblogs.com/Dup4/p/9952552.html
Copyright © 2011-2022 走看看