zoukankan      html  css  js  c++  java
  • CCPC2018-湖南全国邀请赛 Solution

    A - Easy $h$-index

    后缀扫一下

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 200010
     6 
     7 int n;
     8 ll arr[N];
     9 
    10 inline int work()
    11 {
    12     ll sum = 0;
    13     for (int i = n; i >= 0; --i)
    14     {
    15         sum += arr[i];
    16         if (sum >= i) return i;
    17     }    
    18     return 0;
    19 }
    20 
    21 int main()
    22 {
    23     while (scanf("%d", &n) != EOF)
    24     {
    25         for (int i = 0; i <= n; ++i) scanf("%lld", arr + i);
    26         printf("%d
    ", work());
    27     }
    28     return 0;
    29 }
    View Code

    B - Higher $h$-index

    题意:有n个小时的工作量,在一篇paper上工作x小时,就能得到$a cdot x$ 次引用,每增加一篇paper ,前面的paper 引用次数就+1 ,求h-index

    思路:给每一篇paper一个小时,那么arr[]相当于 011111111111  一共有 a + n - 1 个1

    然后要满足不等式$a + n - 1 - h + 1 >= h$ 

    化简后便是 $h <= frac{a + n}{2}$

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

    C - Just $h$-index

    题意:给n个paper,给出每个paper的引用次数,每次询问给出 l, r 求只有这个区间内的paper有效,有h-index

    思路:主席树维护,二分h 复杂度$O(n * log(n)^2)$

      1 #include <bits/stdc++.h>
      2 using namespace std;
      3 
      4 #define N 100010
      5 #define M N * 30
      6 #define ll long long
      7 
      8 int n, q, u, v;
      9 int arr[N];
     10 int T[N], L[M], R[M], C[M], tot;
     11 
     12 inline int build(int l, int r)
     13 {
     14     int root = tot++;
     15     C[root] = 0;
     16     if (l < r)
     17     {
     18         int mid = (l + r) >> 1;
     19         L[root] = build(l, mid);
     20         R[root] = build(mid + 1, r);
     21     }
     22     return root;
     23 }
     24 
     25 inline int update(int root, int pos)
     26 {
     27     int newroot = tot++, tmp = newroot;
     28     C[newroot] = C[root] + 1;
     29     int l = 1, r = n;
     30     while (l < r)
     31     {
     32         int mid = (l + r) >> 1;
     33         if (pos <= mid)
     34         {
     35             L[newroot] = tot++, R[newroot] = R[root];
     36             newroot = L[newroot], root = L[root];
     37             r = mid;
     38         }
     39         else
     40         {
     41             L[newroot] = L[root], R[newroot] = tot++;
     42             newroot = R[newroot], root = R[root];
     43             l = mid + 1;
     44         }
     45         C[newroot] = C[root] + 1;
     46     }
     47     return tmp;
     48 }
     49 
     50 inline int query(int left_root, int right_root, int pos)
     51 {
     52     int res = 0;
     53     int l = 1, r = n;
     54     while (l < r)
     55     {
     56         int mid = (l + r) >> 1;
     57         if (pos <= mid)
     58         {
     59             left_root = L[left_root];
     60             right_root = L[right_root];
     61             r = mid;
     62         }
     63         else
     64         {
     65             res += C[L[left_root]] - C[L[right_root]];
     66             left_root = R[left_root];
     67             right_root = R[right_root];
     68             l = mid + 1;
     69         }
     70     } 
     71     return res;
     72 }
     73 
     74 
     75 int main()
     76 {
     77     while (scanf("%d%d", &n, &q) != EOF)
     78     {
     79         for (int i = 1; i <= n; ++i) scanf("%d", arr + i);
     80         tot = 0; T[n + 1] = build(1, n);
     81         for (int i = n; i >= 1; --i) T[i] = update(T[i + 1], arr[i]);
     82         for (int i = 1, u, v; i <= q; ++i)
     83         {
     84             scanf("%d%d", &u, &v);
     85             int l = 1, r = v - u + 1, ans; 
     86             while (r - l >= 0)
     87             {
     88                 int mid = (l + r) >> 1; 
     89                 int tot = v - u + 1 - query(T[u], T[v + 1], mid);
     90                 if (tot >= mid)
     91                 {
     92                     ans = mid;
     93                     l = mid + 1;
     94                 }
     95                 else
     96                     r = mid - 1;
     97             }
     98             printf("%d
    ", ans);
     99         }
    100     
    101     }
    102     return 0;
    103 }
    View Code

    D - Circular Coloring

    留坑。

    E - From Tree to Graph

    题意:给出一棵树 定义$f_i[u] = 去掉点u后的联通分量个数$ 定义$z_i = f_i(0) oplus f_i(1)  oplus ... oplus f_i(n - 1)$

     $x_i = (a cdot x_{i - 1} + b cdot y_{y - 1} + z_{i - 1}) pmod n$

    $y_i = (b cdot x_{i - 1} + a cdot y_{i - 1} + z_{i - 1}) pmod n$

    求 $x_m, y_m$

    思路:先求出$z_0$ 刚开始的联通分量个数就是每个点的出入度,然后根据异或性质,异或两次相当于消除,每次假如一条边必定形成一个环,然后并查集缩点

      1 #include <bits/stdc++.h>
      2 using namespace std; 
      3 
      4 #define N 10010
      5 
      6 struct Edge
      7 {
      8     int to, nx;
      9     inline Edge() {}
     10     inline Edge(int to, int nx) : to(to), nx(nx) {}
     11 }edge[N << 1];
     12 
     13 int n, m, a, b, x, y, ans;
     14 int head[N], pos, sz[N];
     15 int rmq[N << 1], F[N << 1], P[N], fa[N], deep[N], cnt; 
     16 int pre[N];
     17 
     18 struct ST
     19 {
     20     int mm[N << 1];
     21     int dp[N << 1][20];
     22     inline void init(int n)
     23     {
     24         mm[0] = -1;
     25         for (int i = 1; i <= n; ++i)
     26         {
     27             mm[i] = ((i & (i - 1)) == 0) ? mm[i - 1] + 1 : mm[i - 1];
     28             dp[i][0] = i;
     29         }
     30         for (int j = 1; j <= mm[n]; ++j)
     31         {
     32             for (int i = 1; i + (1 << j) - 1 <= n; ++i)
     33             {
     34                 dp[i][j] = rmq[dp[i][j - 1]] < rmq[dp[i + (1 << (j - 1))][j - 1]] ? dp[i][j - 1] : dp[i + (1 << (j - 1))][j - 1];
     35             }
     36         }
     37     }
     38     inline int query(int a, int b)
     39     {
     40         if (a > b) swap(a, b);
     41         int k = mm[b - a + 1];
     42         return rmq[dp[a][k]] <= rmq[dp[b - (1 << k) + 1][k]] ? dp[a][k] : dp[b - (1 << k) + 1][k];
     43     }
     44 }st;
     45 
     46 inline void Init()
     47 {
     48     memset(head, -1, sizeof head);
     49     memset(sz, 0, sizeof sz); 
     50     pos = 0; cnt = 0; ans = 0;
     51     for (int i = 1; i <= n; ++i) pre[i] = i;
     52 }
     53 
     54 inline void addedge(int u, int v)
     55 {
     56     edge[++pos] = Edge(v, head[u]); head[u] = pos;
     57 }
     58 
     59 inline void DFS(int u)
     60 {
     61     F[++cnt] = u; 
     62     rmq[cnt] = deep[u];
     63     P[u] = cnt;
     64     for (int it = head[u]; ~it; it = edge[it].nx) 
     65     {
     66         int v = edge[it].to;
     67         if (v == fa[u]) continue;
     68         fa[v] = u; deep[v] = deep[u] + 1;
     69         DFS(v); 
     70         F[++cnt] = u;
     71         rmq[cnt] = deep[u];
     72     }
     73 }
     74 
     75 inline void init_lca(int root, int node_num)
     76 {
     77     fa[root] = 0; deep[0] = 0;  
     78     DFS(root);
     79     st.init(2 * node_num - 1); 
     80 }
     81 
     82 inline int query_lca(int u, int v)
     83 {
     84     return F[st.query(P[u], P[v])];
     85 }
     86 
     87 inline int find(int x)
     88 {
     89     if (pre[x] != x)
     90         pre[x] = find(pre[x]);
     91     return pre[x]; 
     92 }
     93 
     94 inline void join(int x, int y)
     95 {
     96     x = find(x); 
     97     if (deep[fa[x]] <= deep[y] || fa[x] == 0) return;
     98     ans ^= sz[fa[x]] ^ (sz[fa[x]] - 1); 
     99     --sz[fa[x]]; 
    100     pre[x] = fa[x];
    101     join(fa[x], y); 
    102 }
    103 
    104 inline void Run() 
    105 {
    106     while (scanf("%d%d%d%d%d%d", &n, &m, &a, &b, &x, &y) != EOF) 
    107     {
    108         Init();
    109         for (int i = 1, u, v; i < n; ++i)
    110         {
    111             scanf("%d%d", &u, &v); ++u, ++v; ++sz[u], ++sz[v];
    112             addedge(u, v); addedge(v, u); 
    113         }
    114         init_lca(1, n);
    115         for (int i = 1; i <= n; ++i) ans ^= sz[i];  
    116         for (int i = 1; i <= m; ++i)
    117         {
    118             int nx = (a * x + b * y + ans) % n;
    119             int ny = (b * x + a * y + ans) % n;
    120             x = nx, y = ny;  
    121             join(x + 1, query_lca(x + 1, y + 1));
    122         }
    123         printf("%d %d
    ", x, y); 
    124     }
    125 }
    126 
    127 int main()
    128 {
    129     #ifdef LOCAL 
    130         freopen("Test.in", "r", stdin);
    131     #endif 
    132 
    133     Run();
    134     return 0;
    135 }
    View Code

    F - Sorting

    公式化简,结构体排序

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 1010
     6 
     7 struct node
     8 {
     9     int id;
    10     ll a, b, c, sum;
    11     inline void scan(int _id)
    12     {
    13         scanf("%lld%lld%lld", &a, &b, &c);
    14         sum = a + b;
    15         id = _id;
    16     }    
    17     inline bool operator < (const node &r) const
    18     {
    19         ll t1 = sum * r.c, t2 = r.sum * c;
    20         return t1 < t2 || t1 == t2 && id < r.id;
    21     }
    22 }arr[N];
    23 
    24 int n;
    25 
    26 int main()
    27 {
    28     while (scanf("%d", &n) != EOF)
    29     {
    30         for (int i = 1; i <= n; ++i) arr[i].scan(i);
    31         sort(arr + 1, arr + 1 + n);
    32         for (int i = 1; i <= n; ++i) printf("%d%c", arr[i].id," 
    "[i == n]);
    33     }
    34     return 0;
    35 }
    View Code

    G - String Transformation

    题意:给出一个串a和串b,每次可以在串a中添加 {"aa", "bb", "abab"} 问能否将串a变成串b

    思路:显然 两个串的c的数量不同是不可以变的 然后以c为间隔,分成若干个间隔,每个间隔里面的a,b差值不为偶数也是没法变

     1 #include<bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 const int maxn = 1e4 + 10;
     6 
     7 int a1[maxn], b1[maxn], c1[maxn];
     8 int a2[maxn], b2[maxn], c2[maxn];
     9 char str1[maxn], str2[maxn];
    10 
    11 int main()
    12 {
    13     while(~scanf("%s", str1 + 1))
    14     {
    15         scanf("%s", str2 + 1);
    16         int n = strlen(str1 + 1);
    17         int m = strlen(str2 + 1);
    18         int cnt1 = 0;
    19         for(int i = 1; i <= n; ++i)
    20         {
    21             cnt1 += (str1[i] == 'c');
    22         }
    23         int cnt2 = 0;
    24         for(int i = 1; i <= m; ++i)
    25         {
    26             cnt2 += (str2[i] == 'c');
    27         }
    28         if(cnt1 != cnt2)
    29         {
    30             puts("No");
    31             continue;
    32         }
    33         c1[0] = c2[0] = 0;
    34         cnt1 = cnt2 = 1;
    35         for(int i = 1; i <= n; ++i)
    36         {
    37             a1[i] = a1[i - 1] + (str1[i] == 'a');
    38             b1[i] = b1[i - 1] + (str1[i] == 'b');
    39             if(str1[i] == 'c')
    40             {
    41                 c1[cnt1++] = i;
    42             }
    43         }
    44         c1[cnt1++] = n;
    45         for(int i = 1; i <= m; ++i)
    46         {
    47             a2[i] = a2[i - 1] + (str2[i] == 'a');
    48             b2[i] = b2[i - 1] + (str2[i] == 'b');
    49             if(str2[i] == 'c')
    50             {
    51                 c2[cnt2++] = i;
    52             }
    53         }
    54         c2[cnt2++] = m;
    55         bool flag = true;
    56         for(int i = 1; i < cnt1; ++i)
    57         {
    58             if((a1[c1[i]] - a1[c1[i - 1]]) % 2 != (a2[c2[i]] - a2[c2[i - 1]]) % 2 || (b1[c1[i]] - b1[c1[i - 1]]) % 2 != (b2[c2[i]] - b2[c2[i - 1]]) % 2)
    59             {
    60                 flag = false;
    61             }
    62         }
    63         puts(flag ? "Yes" : "No");
    64     }
    65     return 0;
    66 }
    View Code

    H - Infinity

    留坑。

    I - Longest Increasing Subsequence

    题意:给出n个数,有若干个数是0,定义$F[i]$ 为将所有0变成i后的最长上升子序列长度  求$sum_{i = 1}^{i = n} i cdot F[i]$

    思路:预处理出$dp[], dp2[]$ $dp[i]$表示以$i$结尾的最长上升子序列长度,$dp2[i]$ 表示以$i$开头的最长上升子序列长度

    我们考虑$F[i] = (Minlen, Minlen + 1)$

    我们先求出 去掉所有0的最长上升子序列长度  然后考虑 $dp[i] + dp2[j] = m$  并且 $[i, j]$ 中有0存在 并且 $arr[i] < arr[j]$  那么

    $x in [arr[i] + 1, arr[j] - 1]$ 的时候 $F[x] = len + 1$

     1 #include <bits/stdc++.h>
     2 using namespace std; 
     3 
     4 #define N 100010 
     5 #define INF 0x3f3f3f3f
     6 #define ll long long
     7 
     8 int n, m;
     9 int dp[N], dp2[N], arr[N], brr[N], a[N]; 
    10 
    11 inline void LIS()
    12 {
    13     int len = 0; brr[1] = 0; 
    14     for (int i = 1; i <= n; ++i)
    15     { 
    16         if (arr[i] == 0) continue;  
    17         int pos = lower_bound(brr + 1, brr + 1 + len, arr[i]) - brr;
    18         if (pos > len) ++len;  
    19         dp[i] = pos; brr[pos] = arr[i];
    20     }
    21     m = len; len = 0; brr[1] = 0;  
    22     for (int i = n; i >= 1; --i)
    23     {
    24         if (arr[i] == 0) continue; 
    25         int pos = lower_bound(brr + 1, brr + 1 + len, -arr[i]) - brr;
    26         if (pos > len) ++len; 
    27         dp2[i] = pos; brr[pos] = -arr[i]; 
    28     } 
    29 } 
    30 
    31 
    32 inline void Run() 
    33 {
    34     while (scanf("%d", &n) != EOF)
    35     {
    36         for (int i = 1; i <= n; ++i) scanf("%d", arr + i); LIS(); 
    37         memset(a, 0, sizeof a); memset(brr, 0x3f, sizeof brr); brr[0] = 0;  
    38         int now = 0;
    39         for (int i = 1; i <= n; ++i) 
    40         {
    41             if (arr[i] == 0) 
    42             {
    43                 for (int j = now + 1; j < i; ++j) 
    44                 {
    45                     brr[dp[j]] = min(brr[dp[j]], arr[j]);   
    46                 }
    47                 now = i; 
    48                 continue;
    49             }  
    50             if (now && brr[m - dp2[i]] < arr[i]) 
    51             { 
    52                 a[brr[m - dp2[i]] + 1]++;
    53                 a[arr[i]]--; 
    54             }
    55         } 
    56         if (now && brr[m] != INF)   
    57         { 
    58             a[brr[m] + 1]++; 
    59         }
    60         for (int i = 1; i <= n; ++i) a[i] += a[i - 1];
    61         ll ans = 0; 
    62         for (int i = 1; i <= n; ++i) ans += (ll)i * (m + (a[i] ? 1 : 0));  
    63         printf("%lld
    ", ans);  
    64     }
    65 }
    66 
    67 int main()
    68 {
    69     #ifdef LOCAL 
    70         freopen("Test.in", "r", stdin);
    71     #endif 
    72 
    73     Run();
    74     return 0;
    75 }
    View Code

    J - Vertex Cover

    题意:有n个点,标号为0 - n - 1每个点的权值就是$2_i$ i 为标号,alice 任意选择一种边集,bob选择一种权值和最小的边际覆盖它的边集,覆盖的定义为alice中每条边中至少有一个点在bob的边集当中,并且权值和为k

    思路:因为权值为2的幂,所以如果bob存在一种选择满足要求,只有一种,那就是k

    那么相当于固定bob的选择,找alice有多少种选择被bob覆盖

    从左往右扫,如果遇到一个点是0,那么这个点可以和前面的1连一条边

    如果遇到一个点是1,那么这个点至少要在前面选择一个没有选的点相连,其他点可连可不连,所有可能性相乘

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define MOD 1000000007
     6 #define N 100010
     7 
     8 ll Bit[N];
     9 
    10 inline void Init()
    11 {
    12     Bit[0] = 1;
    13     for (int i = 1; i <= 100000; ++i) Bit[i] = (Bit[i - 1] << 1) % MOD;
    14 }
    15 
    16 int n;
    17 char s[N];
    18 
    19 int main()
    20 {
    21     Init();
    22     while (scanf("%d", &n) != EOF)
    23     {
    24         scanf("%s", s);
    25         int len = strlen(s);
    26         ll ans = 1; int k = n - len, cnt = 0;
    27         for (int i = 0; i < len; ++i, ++k)
    28         {
    29             if (s[i] == '1')
    30             {
    31                 ans = (ans *(Bit[k] - Bit[cnt] + MOD) % MOD) % MOD; 
    32                 ++cnt;
    33             }
    34             else
    35             {
    36                 ans = (ans * Bit[cnt]) % MOD;
    37             }
    38         }
    39         printf("%lld
    ", ans);
    40     }
    41     return 0;
    42 }
    View Code

    K - 2018

    题意:给出a, b, c, d, 找出有多少个二元组(x, y) 满足 $ x cdot y equiv 0 pmod 2018$

    思路:显然,2018只能拆成1009 * 2

    那么只要在(a, b) 中有多少1009 倍数 2008倍数  然后计算 注意去重

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 
     6 ll x, y;
     7 ll a, b, c, d;
     8 
     9 int main()
    10 {
    11     while (scanf("%lld%lld%lld%lld", &a, &b, &c, &d) != EOF)
    12     {
    13         ll ans = 0;
    14         
    15         x = (b / 2018) - ((a - 1) / 2018);
    16         y = (d - c + 1);
    17         ans += x * y;
    18 
    19         x = (d / 2018) - ((c - 1) / 2018);
    20         y = (b - a + 1);
    21         ans += x * y;
    22 
    23         x = (b / 2018) - ((a - 1) / 2018);
    24         y = (d / 2018) - ((c - 1) / 2018);
    25         ans -= x * y;
    26 
    27         x = (((b / 1009) + 1) / 2) - ((((a - 1) / 1009) + 1) / 2);
    28         y = ((d / 2) - ((c - 1) / 2)) - ((d / 2018) - ((c - 1) / 2018));
    29         ans += x * y;
    30 
    31         x = (((d / 1009) + 1) / 2) - ((((c - 1) / 1009) + 1) / 2);
    32         y = ((b / 2) - ((a - 1) / 2)) - ((b / 2018) - ((a - 1) / 2018));
    33         ans += x * y;
    34 
    35         printf("%lld
    ", ans);
    36     }
    37     return 0;
    38 }
    View Code
  • 相关阅读:
    zoj 2316 Matrix Multiplication 解题报告
    BestCoder7 1001 Little Pony and Permutation(hdu 4985) 解题报告
    codeforces 463C. Gargari and Bishops 解题报告
    codeforces 463B Caisa and Pylons 解题报告
    codeforces 463A Caisa and Sugar 解题报告
    CSS3新的字体尺寸单位rem
    CSS中文字体对照表
    引用外部CSS的link和import方式的分析与比较
    CSS样式表引用方式
    10个CSS简写/优化技巧
  • 原文地址:https://www.cnblogs.com/Dup4/p/9593797.html
Copyright © 2011-2022 走看看