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