Codeforces Round #656 (Div. 3)
A. Three Pairwise Maximums #构造
题意
给定三个正整数x,y,z,要求找出正整数a,b,c,满足x=max(a,b),y=max(a,c),z=max(b,c)
分析
我们可以先将x,y,z降序排序得到z≤y≤x。由于x是a,b,c三者最值,且通过三个关系中x所代表的数字一定出现两次,可以推断出,y=x,如果最值没有出现两次,说明我们不可能构造出a,b,c。
既然题目让我们构造,构造且要满足max(a,b)=max(a,c),那么不妨设a为最大值,即a=x=y。由于z能推出b,c关系,我们又不妨将b赋为z(三值中第二大)。三者最小值不易准确确定,直接将c赋值为1,作为三者中的最小值,十分稳妥。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <algorithm> #include <cstdio> #include <iostream> using namespace std; typedef long long ll; const int MAXN = 1e5 + 5; const int MOD = 1e4 + 7; int n, m, q; int main(){ scanf("%d", &q); while(q--){ int x, y, z; scanf("%d%d%d", &x, &y, &z); if(x<y) swap(x,y); if(x<z) swap(x,z); if(y<z) swap(y,z); if(x != y) { printf("NO\n"); continue; } else{ printf("YES\n"); printf("%d %d %d\n", x, z, 1); } } return 0; }
|
C. Make It Good #贪心
题意
“好数组”定义为,一个数组b,我们只从该数组最左边,或者最右边,将所有元素依次取出并放到c数组,该c数组是个不降序列,则称b数组为“好数组”。
现给定数组a,你需要从数组a的前几个元素删去,得到一个“好数组”。现要你求出删除的前几个元素至少需要多少。比如数组a={4 3 3 8 4 5 2},你至少需要删除前面4个元素,得到的数组b={4 5 2}才是个好数组。
分析
不难分析,“好数组”中的元素关系必然是b1≤b2≤...≤bmx≥...≥bk,其中bmx为数组b中最大值(不一定是数组a中最大值),简单来说,我们就是要从a数组中找到“山峰”。
由于我们只能删除数组a中前面几个元素,因而后面元素受到的影响很少,于是我们用一右指针hi,从数组a的后面往前面遍历,只要a[hi−1]≥a[hi]就往前进(相当于走上坡),一旦遇到a[hi−1]≤a[hi]说明到达极值点。我们再继续往前面(往数组左端)遍历,只要a[hi−1]≤a[hi]就往前进(相当于走下坡),一旦遇到a[hi−1]≥a[hi]说明到达我们到达山底,即a[1,...hi−1]的元素都需要删去,a[hi,n]方为好数组。敲代码时注意下边界。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <algorithm> #include <cstdio> #include <cstring> #include <iostream> using namespace std; typedef long long ll; const int MAXN = 2e5 + 5; int n, m, q; int a[MAXN]; int main(){ scanf("%d", &q); while(q--){ scanf("%d", &n); for(int i =1 ; i <= n; i++) scanf("%d", &a[i]); int hi = n; while(hi >= 1 && a[hi-1] >= a[hi]) hi--; while(hi >= 1 && a[hi - 1] <= a[hi]) hi--; if(hi - 1 >= 0) printf("%d\n", hi - 1); else printf("0\n"); } return 0; }
|
D. a-Good String #暴力深搜 #分治
题意
“a-好串”定义为,不小于一个元素的串,满足以下其中一个条件即可:
- 若长度为1,且包含的字符恰好为a。
- 若长度大于1,且它的左半部分所有字符均为a,而另一半的串是“a+1-好串”(a+1字符,即为字符a在字母表中下一个字符)
- 若长度大于1,且它的右半部分所有字符均为a,而另一半的串是“a+1-好串”
t(≤2×105)组询问,给定长度为n(其中∑n≤2×105)串,你可以对串中任意字符转变为其他任意字符,每个字符的转变作为一次操作,现要你求出将串转变为“a−好串”的最少次数
分析
先将串中所有种字符进行前缀和统计,然后对于串的前后部分暴力搜索一下即可,因为递归下来,大约有logn种子串,层数大约为十多层,O(nlogn)复杂度能够通过t组询问。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include <cstdio> #include <cstring> #include <iostream> #include <queue> #include <string> using namespace std; typedef long long ll; const int MAXN = 150000; int q, n, sum[30][MAXN]; string str; int dfs(int lo, int hi, int cur){ int mid = (lo + hi) >> 1, len = hi - lo + 1; if(len <= 1) return len - sum[cur][hi] + sum[cur][hi - 1]; int pre = (len >> 1) - sum[cur][mid] + sum[cur][lo - 1]; int lat = (len >> 1) - sum[cur][hi] + sum[cur][mid]; int res = min(dfs(lo, mid, cur+1) + lat, dfs(mid+1, hi, cur+1) + pre); return res; } void preCal(){ for (int i = 1; i <= 26; i++){ for (int j = 0; j < str.length(); j++){ sum[i][j + 1] = sum[i][j]; if(str[j] - 'a' + 1 == i) sum[i][j + 1]++; } } } int main(){ scanf("%d", &q); while(q--){ scanf("%d", &n); cin >> str; preCal(); printf("%d\n", dfs(1, n, 1)); } }
|
E. Directing Edges #拓扑排序
题意
给定一个图,里面既包含有向边,也包含无向边,并保证初始情况下的图不存在平行边与自环,现要你将图中所有无向边改变为有向边(方向自定义),使得图不存在任何一个有向环。如果无法保证不出现有向环,输出"NO"。否则需要你输出所有边的连接信息。
分析
容易知道,初始情况下的无向边并不会影响图是否存在有向环,应关注于当前的所有有向边所组成的图。如何判断是否存在有向环,利用拓扑排序算法即可,但别忘了要将拓扑序列存下来,这是用于判断无向边指向的方向。如果一条无向边中的顶点a的拓扑序小于顶点b,那么a应该指向b,反之,让b指向a。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| #include <cstdio> #include <cstring> #include <iostream> #include <queue> #include <stack> #include <string> #include <vector> using namespace std; typedef long long ll; const int MAXN = 2e5+5; int q, n, m; struct Edge{ int u, v; } E[MAXN << 1]; struct BuildEdge{ int to, nextNbr; } BE[MAXN << 1]; int H[MAXN], tot = 0, InD[MAXN], num = 0; int ans[MAXN]; void addEdge(int u, int v){ tot++; BE[tot] = {v, H[u]}; H[u] = tot; } bool ToSort(){ queue<int> myque; int res = 0; for(int i = 1; i <= n; i++){ if(InD[i] == 0){ myque.push(i); ans[i] = ++res; } } while(!myque.empty()){ int cur = myque.front(); myque.pop(); for(int i = H[cur]; i >= 0; i = BE[i].nextNbr){ int v = BE[i].to; InD[v]--; if(InD[v] == 0){ myque.push(v); ans[v] = ++res; } } } return (res != n); } void Init(){ memset(H, -1, sizeof(H)); memset(ans, 0, sizeof(ans)); memset(InD, 0, sizeof(InD)); tot = num = 0; for (int i = 1; i <= m; i++) BE[i] = {-1, -1}; } int main(){ scanf("%d", &q); while(q--){ scanf("%d%d", &n, &m); Init(); for (int i = 1, u, v, opt; i <= m; i++){ scanf("%d%d%d", &opt, &u, &v); E[++num] = {u, v}; if(opt == 1){ addEdge(u, v); InD[v]++; } } bool isLoop = ToSort(); if(isLoop) printf("NO\n"); else{ printf("YES\n"); for(int i = 1; i <= m; i++){ int u = E[i].u, v = E[i].v; if(ans[u] < ans[v]) printf("%d %d\n", u, v); else printf("%d %d\n", v, u); } } } return 0; }
|