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\n", 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\n", (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\n", 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\n", 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," \n"[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\n", 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\n", 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\n", ans);
36     }
37     return 0;
38 }
View Code

 

posted @ 2018-09-05 18:36  Dup4  阅读(427)  评论(0编辑  收藏  举报