zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    陶瓷电容的结构、工艺、失效模式
    Vue.js最佳实践
    Vue 超快速学习
    CSS 小技巧
    HTML5 Canvas
    webkit下面的CSS设置滚动条
    Some untracked working tree files would be overwritten by checkout. Please move or remove them before you can checkout. View them
    JSCS: Please specify path to 'JSCS' package
    React中ref的使用方法
    React 60S倒计时
  • 原文地址:https://www.cnblogs.com/Dup4/p/10147328.html
Copyright © 2011-2022 走看看