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 - 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

留坑。

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

猜你喜欢

转载自www.cnblogs.com/Dup4/p/9593797.html