• 2017年浙江中医药大学程序设计竞赛 Solution


    训练地址

    A:

    树剖板子题

    求最小值的时候要注意值是不是有负数,如果有,初值要置为$-INF$

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3  
      4 #define N 30010
      5 #define INF 0x3f3f3f3f
      6 int n, q, arr[N];
      7 vector <int> G[N];
      8  
      9 int fa[N], deep[N], sze[N], son[N], top[N], p[N], fp[N], cnt;
     10 void DFS(int u)
     11 {
     12     sze[u] = 1;
     13     for (auto v : G[u]) if (v != fa[u])
     14     {
     15         fa[v] = u;
     16         deep[v] = deep[u] + 1;
     17         DFS(v);
     18         sze[u] += sze[v];
     19         if (!son[u] || sze[v] > sze[son[u]]) son[u] = v;
     20     }
     21 }
     22  
     23 void getpos(int u, int sp)
     24 {
     25     top[u] = sp;
     26     p[u] = ++cnt;
     27     fp[cnt] = u;
     28     if (!son[u]) return;
     29     getpos(son[u], sp);
     30     for (auto v : G[u]) if (v != fa[u] && v != son[u])
     31         getpos(v, v);
     32 }
     33  
     34 namespace SEG
     35 {
     36     struct node
     37     {
     38         int Max, sum;
     39         node () {}
     40         node (int Max, int sum) : Max(Max), sum(sum) {}
     41         node operator + (const node &other) const { return node(max(Max, other.Max), sum + other.sum); }
     42     }a[N << 2], res;
     43     void build(int id, int l, int r)
     44     {
     45         if (l == r)
     46         {
     47             a[id] = node(arr[fp[l]], arr[fp[l]]);
     48             return;
     49         }
     50         int mid = (l + r) >> 1;
     51         build(id << 1, l, mid);
     52         build(id << 1 | 1, mid + 1, r);
     53         a[id] = a[id << 1] + a[id << 1 | 1];
     54     }
     55     void update(int id, int l, int r, int pos, int val)
     56     {
     57         if (l == r)
     58         {
     59             a[id] = node(val, val);
     60             return;
     61         }
     62         int mid = (l + r) >> 1;
     63         if (pos <= mid) update(id << 1, l, mid, pos, val);
     64         else update(id << 1 | 1, mid + 1, r, pos, val);
     65         a[id] = a[id << 1] + a[id << 1 | 1];
     66     }
     67     void query(int id, int l, int r, int ql, int qr)
     68     {
     69         if (l >= ql && r <= qr)
     70         {
     71             res = res + a[id];
     72             return;
     73         }
     74         int mid = (l + r) >> 1;
     75         if (ql <= mid) query(id << 1, l, mid, ql, qr);
     76         if (qr > mid) query(id << 1 | 1, mid + 1, r, ql, qr);
     77     }
     78 }
     79  
     80 void query(int u, int v)
     81 {
     82     while (top[u] != top[v])
     83     {
     84         if (deep[top[u]] < deep[top[v]]) swap(u, v);
     85         SEG::query(1, 1, n, p[top[u]], p[u]);
     86         u = fa[top[u]];
     87     }
     88     if (deep[u] > deep[v]) swap(u, v);
     89     SEG::query(1, 1, n, p[u], p[v]);
     90 }
     91  
     92 int main()
     93 {
     94     while (scanf("%d%d", &n, &q) != EOF)
     95     {
     96         cnt = 0;
     97         memset(son, 0, sizeof son);
     98         for (int i = 1; i <= n; ++i) scanf("%d", arr + i), G[i].clear();
     99         for (int i = 1, u, v; i < n; ++i)
    100         {
    101             scanf("%d%d", &u, &v);
    102             G[u].push_back(v);
    103             G[v].push_back(u);
    104         }
    105         DFS(1); getpos(1, 1); SEG::build(1, 1, n);
    106         for (int i = 1, op, x, y; i <= q; ++i)
    107         {
    108             scanf("%d%d%d", &op, &x, &y);
    109             if (op == 2) SEG::update(1, 1, n, p[x], y);
    110             else
    111             {
    112                 SEG::res = SEG::node(-INF, 0);
    113                 query(x, y);
    114                 printf("%d
    ", op == 0 ? SEG::res.Max : SEG::res.sum);
    115             }  
    116         }
    117     }
    118     return 0;
    119 }
    View Code

    B:

    $b^2 = 2 cdot a cdot (a + 1) ^ 2$

    $b = sqrt{2 cdot a} cdot (a +1)$

    所以a一定是个平方数的两倍

    即$a = 2 cdot i^2 $

    枚举出答案,再二分查找

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3  
     4 #define ull unsigned long long
     5 #define N 6000020
     6 ull res[N];
     7  
     8 int main()
     9 {
    10     for (int i = 0; i < N; ++i)
    11         res[i] = (ull)2 * i * ((ull)2 * i * i + 1);
    12     //cout << res[N - 1] << endl;
    13     int t; cin >> t;
    14     while (t--)
    15     {
    16         ull n; scanf("%llu", &n);
    17         int pos = lower_bound(res, res + N, n) - res;
    18         printf("%llu
    ", res[pos]); 
    19     }
    20     return 0;
    21 }
    View Code

    C:

    $倒着推过来$

    $对于'u' 记录一下最近的位置$

    $对于'm',记录一下离他最近的'u'的位置$

    $对于'c' , 记录一下离(离他最近的'm'的)最近的'z'的位置$

    $对于'z',可以直接求答案$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3  
     4 #define N 100010
     5 #define INF 0x3f3f3f3f
     6 char s[N];
     7 int f[4];
     8  
     9 int main()
    10 {
    11     while (scanf("%s", s + 1) != EOF)
    12     {  
    13         memset(f, INF, sizeof f);
    14         for (int i = strlen(s + 1); i >= 1; --i)
    15         {
    16             if (s[i] == 'u') f[3] = i;
    17             else if (s[i] == 'm')
    18             {
    19                 if (f[3] != INF)
    20                     f[2] = min(f[2], f[3] - 1);
    21             }
    22             else if (s[i] == 'c')
    23             {
    24                 if (f[2] != INF)
    25                     f[1] = min(f[1], f[2] - 1);
    26             }
    27             else if (s[i] == 'z')
    28             {
    29                 if (f[1] != INF)
    30                     f[0] = min(f[0], f[1] - i - 1);
    31             }
    32         }
    33         printf("%d
    ", f[0] == INF ? -1 : f[0]);
    34     }
    35     return 0;
    36 }
    View Code

    D:

    贪心

    考虑所有物品都要放进去

    那么肯定先放$a_i <= b_i的物品,因为这些物品放进去背包会扩容$

    那么放这些物品的时候按照$a_i从小到大的顺序排放$

    $因为如果小的都放不下,那么大的肯定放不下,但是大的可以等小的放进去扩容之后可能就可以放下$

    那么剩下的物品按照$(a_i - b_i)从小到大的顺序排放$

    $因为我们要放一件物品要尽量使得背包缩小的体积较小,这样对后面物品的影响也较小$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3   
     4 #define ll long long
     5 #define N 100010
     6 int t, n; ll v;
     7 struct node
     8 {
     9     int a, b;
    10     node () {}
    11     node (int a, int b) : a(a), b(b) {}
    12 };
    13 vector <node> p, q;
    14   
    15 bool ok()
    16 {
    17     for (auto it : p)
    18     {
    19         if (v < it.a) return false;
    20         v += it.b - it.a;
    21     }
    22     for (auto it : q)
    23     {
    24         if (v < it.a) return false;
    25         v += it.b - it.a;
    26     }
    27     return true;
    28 }
    29   
    30 int main()
    31 {
    32     scanf("%d", &t);
    33     while (t--)
    34     {
    35         scanf("%d%lld", &n, &v);
    36         p.clear(), q.clear();
    37         for (int i = 1, a, b; i <= n; ++i)
    38         {
    39             scanf("%d%d", &a, &b);
    40             if (a <= b) p.emplace_back(a, b);
    41             else q.emplace_back(a, b);
    42         }
    43         sort(p.begin(), p.end(), [](node x, node y) { return x.a < y.a; });
    44         sort(q.begin(), q.end(), [](node x, node y) { return x.a - x.b > y.a - y.b; });
    45         puts(ok() ? "yes" : "no");
    46     }
    47     return 0;
    48 }
    View Code

    E:

    签到。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3  
     4 #define ll long long
     5 int t;
     6 ll n, k;
     7  
     8 int main()
     9 {
    10     scanf("%d", &t);
    11     while (t--)
    12     {
    13         scanf("%lld%lld", &n, &k);
    14         printf("%lld
    ", k);
    15     }
    16     return 0;
    17 }
    View Code

    F:

    题意:

    给出一个循环节,求这个循环节上的哪些位置,使得从这个位置出发

    不论到达哪个位置,前缀1的个数都大于前缀0的个数

    思路:

    刚开始的想法是线段树的$O(nlogn)做法$

    维护处前缀0的个数和前缀1的个数,然后枚举起始位置,两个起始位置之间$O(logn)转移,T了$

    然后又考虑了单调队列的做法,$维护一个lazy, O(n),过了$

    最后看了看别人的代码,答案是$1的个数-0的个数,晕了$

    感觉,首先复杂度没有算法,很明显的需要线性做法,却要硬刚带$log的$

    再考虑一下,答案为什么是$1的个数-0的个数$

    首先,所有0所处的位置都不可能作为起始位置

    再考虑,有哪些1是不可以的

    我们考虑连续的0,如果有一段连续的$x个0,那么这x个0往前数x个1,这x个1都是不可以的$

    因为肯定至少存在一个位置不满足要求

    $再考虑离散的0,那么离散的0直接理解为连续的1个0即可$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3  
     4 #define N 200010
     5 int t, n, a[N], sum[N], dq[N];
     6  
     7 int main()
     8 {
     9     scanf("%d", &t);
    10     while (t--)
    11     {
    12         scanf("%d", &n);
    13         for (int i = 1; i <= n; ++i)
    14         {
    15             scanf("%d", a + i);
    16             a[i + n] = a[i];
    17         }
    18         int l = 1, r = 0;
    19         for (int i = 1, tmp = 0; i <= n; ++i)
    20         {
    21             tmp += a[i];
    22             sum[i] = 2 * tmp - i;
    23             while (l <= r && sum[dq[r]] > sum[i]) --r;
    24             dq[++r] = i;   
    25         }
    26         int res = 0, lazy = 0;
    27         for (int i = 1; i <= n; ++i)
    28         {
    29             while (l <= r && dq[l] < i) ++l;
    30             if (sum[dq[l]] + lazy > 0) ++res;
    31             sum[i + n] = sum[i + n - 1] + 1 * (a[i + n] ? 1 : -1);
    32             while (l <= r && sum[dq[r]] > sum[i + n]) --r;
    33             lazy += 1 * (a[i] ? -1 : 1);
    34             dq[++r] = i + n;
    35         }
    36         printf("%d
    ", res);
    37     }
    38     return 0;
    39 }
    View Code

    G:

    签到。

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

    H:

    题意:

    将一个n * n矩形分成两个相同的部分,求方案数

    思路:

    n 为奇数 答案为0

    然后从中间开始搜,对称标记

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3  
     4 int t, ans[11], res, n;
     5 int used[20][20];
     6 int Move[][2] =
     7 {
     8     0, -1,
     9     0,  1,
    10     1,  0,
    11    -1,  0,
    12 };
    13  
    14 void DFS(int x, int y)
    15 {
    16     if (x == 0 || y == 0 || x == n || y == n)
    17     {
    18         ++res;
    19         return;
    20     }
    21     for (int i = 0; i < 4; ++i)
    22     {
    23         int nx = x + Move[i][0];
    24         int ny = y + Move[i][1];
    25         if (used[nx][ny] == 0)
    26         {
    27             used[nx][ny] = 1;
    28             used[n - nx][n - ny] = 1;
    29             DFS(nx, ny);
    30             used[nx][ny] = 0;
    31             used[n - nx][n - ny] = 0;
    32         }
    33     }
    34 }
    35  
    36  
    37 int main()
    38 {
    39     for (int i = 1; i < 10; ++i)
    40     {
    41         if (i & 1) ans[i] = 0;
    42         else
    43         {
    44             memset(used, 0, sizeof used);
    45             res = 0; n = i;
    46             used[i / 2][i / 2] = 1;
    47             DFS(i / 2, i / 2);
    48             ans[i] = res / 4;
    49         }
    50     }
    51     scanf("%d", &t);
    52     while (t--)
    53     {
    54         scanf("%d", &n);
    55         printf("%d
    ", ans[n]);
    56     }
    57     return 0;
    58 }
    View Code

    I:

    按题意模拟即可。

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3  
      4 #define N 10010
      5 int t, n;
      6 string str;
      7 string var[N], save[N];
      8 int Size[N], Len[N];
      9 map <string, int> mp;
     10  
     11 void getName(int i, int len)
     12 {
     13     string name = "";
     14     for (; i < len; ++i)
     15     {
     16         if (str[i] == '[')
     17         {
     18             ++i;
     19             break;
     20         }
     21         name += str[i];
     22     }
     23     int big = 0;
     24     for (; i < len; ++i)
     25     {
     26         if (str[i] == ']') break;
     27         big = big * 10 + str[i] - '0';
     28     }
     29     ++n;
     30     mp[name] = n;
     31     var[n] = name;
     32     save[n] = "";
     33     Size[n] = big;
     34     Len[n] = 0;
     35 }
     36  
     37 int main()
     38 {
     39     ios::sync_with_stdio(false);
     40     cin.tie(0); cout.tie(0);
     41     cin >> t; getline(cin, str);
     42     while (t--)
     43     {
     44         n = 0;
     45         mp.clear();
     46         while (1)
     47         {
     48             getline(cin, str);
     49             if (str == "return 0;") break;
     50             if (str[0] == 'c' && str[1] == 'h')
     51             {  
     52                 for (int i = 0, len = str.size(); i < len; ++i) if (str[i] == ' ')
     53                     getName(i + 1, len);               
     54             }
     55             else if (str[0] == 'g')
     56             {
     57                 string name = "";
     58                 str += "
    ";
     59                 int i = 0, len = str.size();
     60                 for (; i < len; ++i) if (str[i] == ' ') 
     61                 {
     62                     ++i;
     63                     break;
     64                 }
     65                 for (; i < len; ++i)
     66                 {
     67                     if (str[i] == ' ')
     68                     {
     69                         ++i;
     70                         break;
     71                     }
     72                     name += str[i];
     73                 }          
     74                 int id = mp[name];
     75                 Len[id] = len - i; 
     76                 string s = "";
     77                 for (int j = 0; i < len && j < Size[id]; ++i, ++j)
     78                     s += str[i];
     79                 save[id] = s;
     80             }
     81             else
     82             {
     83                 string name = "";
     84                 int i = 0, len = str.size();
     85                 for (; i < len; ++i) if (str[i] == ' ')
     86                 {
     87                     ++i;
     88                     break;
     89                 }
     90                 for (; i < len; ++i) name += str[i];
     91                 int id = mp[name];
     92                 string res = save[id];
     93                 int remind = Len[id] - Size[id];
     94                 for (int i = id + 1; remind > 0 && i <= n; ++i)
     95                 {
     96                     res += save[i];
     97                     remind -= Size[i] - Len[i]; 
     98                 }
     99                 if (res.end()[-1] != '
    ') res += "
    ";
    100                 cout << res;
    101             }
    102         }
    103     }
    104     return 0;
    105 }
    View Code

    j:

    考虑如果没有$gcd(x, y) != 1 的限制$

    那么直接处理处b[a[i]]

    再对于$a[b[i]] 直接求答案$

    有这个限制我们可以考虑容斥,可以直接用莫比乌斯函数来容斥

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 100010
     6 int n;
     7 int a[N], b[N];
     8 bool check[N]; int mu[N], prime[N];
     9 void Moblus()
    10 {
    11     memset(check, false, sizeof check);
    12     mu[1] = 1;
    13     int tot = 0;
    14     for (int i = 2; i < N; ++i)
    15     {
    16         if (!check[i])
    17         {
    18             prime[++tot] = i;
    19             mu[i] = -1;
    20         }
    21         for (int j = 1; j <= tot; ++j)
    22         {
    23             if (i * prime[j] >= N) break;
    24             check[i * prime[j]] = true;
    25             if (i % prime[j] == 0)
    26             {
    27                 mu[i * prime[j]] = 0;
    28                 break;
    29             }
    30             else
    31             {
    32                 mu[i * prime[j]] = -mu[i];
    33             }
    34         }
    35     }
    36 }
    37 
    38 ll vis[N];
    39 ll f(int t)
    40 {
    41     ll res = 0;
    42     for (int i = t; i <= n; i += t) ++vis[b[a[i]]];
    43     for (int i = t; i <= n; i += t) res += vis[a[b[i]]];
    44     for (int i = t; i <= n; i += t) --vis[b[a[i]]];
    45     return res;
    46 }
    47 
    48 int main()
    49 {
    50     Moblus();
    51     while (scanf("%d", &n) != EOF)
    52     {
    53         memset(vis, 0, sizeof vis);
    54         for (int i = 1; i <= n; ++i) scanf("%d", a + i);
    55         for (int i = 1; i <= n; ++i) scanf("%d", b + i);
    56         ll res = 0;
    57         for (int i = 1; i <= n; ++i)
    58             res += mu[i] * f(i);
    59         printf("%lld
    ", res);        
    60     }
    61     return 0;
    62 }
    View Code
  • 相关阅读:
    备考C++有感
    使用GridView来获取xml文件数据
    SQL 事务及实例演示
    MySQL数据分析-(12)表操作补充:字段属性
    以字符串为例,谈谈Python到底要学到什么程度
    MySQL数据分析-(9)库操作补充:用户管理和权限管理
    Python流程控制和缩进
    MySQL数据分析-(11)表补充:数据类型
    MySQL数据分析-(8)SQL基础操作之库操作
    外键
  • 原文地址:https://www.cnblogs.com/Dup4/p/10147328.html
Copyright © 2020-2023  润新知