2020大一个人赛(9)题解
A-Rooms and Passages Gym 102215A
题意:给n个数,从起点出发,一直往右走,遇到一个前面出现过其相反数的正数就停下,问对于每个起点都能走多少步。
思路:倒着去递推
- 如果该点是正数,肯定能顺着走,ans[i]=ans[i+1]+1;
- 如果该点是负数,判断该相反数是否存在,若不存在,还是ans[i]=ans[i+1]+1,否则走到前面出现过其相反数的正数,r = min(r, b[-a[i]] - 1); ans[i] = r - i + 1;
具体看代码怎么模拟吧
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<cstring> 5 using namespace std; 6 #define ll long long 7 const int N = 1000005; 8 const int mod = 1e9 + 7; 9 ll a[N],b[N],c[N],ans[N]; 10 int main() 11 { 12 ll i, j, k; 13 ll n, m, t,x,sum=0; 14 cin >> n; 15 for (i = 1; i <= n; i++) 16 cin >> a[i]; 17 ll r = n + 1; 18 for (i = n; i >= 1; i--) 19 { 20 if (a[i] > 0) 21 { 22 ans[i] = ans[i + 1] + 1; 23 b[a[i]] = i;//记录a[i]出现的最靠前的位置 24 } 25 else 26 { 27 if (!b[-a[i]]) 28 { 29 ans[i] = ans[i + 1] + 1;//在i后边没有这种颜色,可通过就是下一个情况加1 30 } 31 else 32 { 33 r = min(r, b[-a[i]] - 1);//寻找能到达的最靠前的位置 34 ans[i] = r - i + 1; 35 } 36 } 37 } 38 for (i = 1; i <= n; i++) 39 cout << ans[i] << " "; 40 41 42 }
B - Rearrange Columns Gym - 102215B
题意:有两行字符串,有‘#’和‘.’,问能否重排(列一起移),使他们连在一起。
思路:模拟即可,判断一下两行都是#的一定能有办法连在一起,或者上面有#下面(相反也是),然后连完之后你怎么排也无所谓(样例不一定就是唯一解)
详情看代码吧!
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<map> 5 #include<cstring> 6 using namespace std; 7 #define ll long long 8 const int N = 1e5+5; 9 const int mod = 1e9 + 7; 10 int main() 11 { 12 ll i, j, k; 13 ll m, t; 14 string s1, s2; 15 cin >> s1 >> s2; 16 ll n = s1.size(); 17 ll a = 0, b = 0, c = 0; 18 for (i = 0; i < n; i++) 19 { 20 if (s1[i] == '#' && s2[i] == '#')a++; 21 else if (s1[i] == '#' && s2[i] == '.')b++; 22 else if (s1[i] == '.' && s2[i] == '#')c++; 23 } 24 if (a || (b && !c) || (c && !b)) 25 { 26 cout << "YES" << endl; 27 { 28 for (i = 0; i < n - a - b - c; i++) 29 cout << '.'; 30 for (i = 0; i < a + b; i++) 31 cout << '#'; 32 for (i = 0; i < c; i++) 33 cout << '.'; 34 cout << endl; 35 for (i = 0; i < n - a - b - c; i++) 36 cout << '.'; 37 for (i = 0; i < b; i++) 38 cout << '.'; 39 for (i = 0; i < a+c; i++) 40 cout << '#'; 41 cout << endl; 42 } 43 } 44 else 45 cout << "NO" << endl; 46 47 48 }
C - Jumps on a Circle Gym - 102215C
题意:一个环从0到p-1,从0开始每次跳1,2,3,···,n-1,n步,问跳n步之后会有多少个位置访问过。
思路:弄一个vis数组,表示访问过的点,注意p为1e7,数组开大点(RE很多次),或者用map记录,去到没标过的点就+1
然后若n>2p,2p次后又一定回到点原点,然后2p+1,2p+2步的效果相当于1,2步(%p就知道了)
这时候观众朋友们告诉我,为什么不是p次呢,因为
你带4进去就知道原因了。所以最少走min(n,2p)次就能知道访问过的点了。
详情问代码吧!
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<cstring> 5 using namespace std; 6 #define ll long long 7 const int N = 1e7+5; 8 const int mod = 1e9 + 7; 9 ll vis[N]; 10 int main() 11 { 12 ll i, j, k; 13 ll p,n, m, t,x,sum=0; 14 cin >> p >> n; 15 vis[0] = 1; 16 ll now = 0; 17 for (i = 1; i <= min(n, 2 * p); i++) 18 { 19 now = (now + i) % p; 20 vis[now] = 1; 21 } 22 for (i = 0; i < p; i++) 23 sum += vis[i]; 24 cout << sum << endl; 25 26 27 }
D - Country Division Gym - 102215D
题意:给你n点,n-1条边(相当于一棵树),每次询问给你一些点染红色,一些点蓝色,问能否通过放些障碍物在边上,使得所有红色的点互相连通,所有蓝色的点连通,而不互相碰见。
思路:LCA(最近公共祖先),就是找公共的父节点,这题是一道LCA经典题,各位可以认真细品题目,get到新知识点你就会成长,至于问怎么实现LCA原理的,我没了解过OvO
解释下LCA,比如4和5的公共父节点是2;4和6的LCA是1;5和7的LCA是1;6和7的LCA是3.
正解思路:
- 先求红色点的lca,再求蓝色点的lca,如果两个lca不在同一棵子树,那么可以分隔开来。
- 如果两个lca有祖先关系,比如红色lca和蓝色lca的lca就是红色lca,那么如果红色点都在红色lca指向蓝色lca的另一条边上,那就可以,否则,说明有红色点在蓝色点的子树下
下面看代码吧
1 #include<iostream> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstdio> 5 #include<cstdlib> 6 #include<cstring> 7 #include<math.h> 8 #include<map> 9 #include<vector> 10 #include<set> 11 #include<queue> 12 #define fori for(i=0;i<n;i++) 13 #define fori1 for(i=1;i<=n;i++) 14 #define inf 9999999 15 #define Check(x,y) (x<n&&x>=0&&y>=0&&y<m) 16 #define IOS ios::sync_with_stdio(false);cin.tie(0) 17 #define ll long long 18 #define inf 0x3f3f3f3f 19 #define eps 1e-6 20 #define pi acos(-1) 21 #define mea (memset(a,0,sizeof(a))) 22 #define myit set<ll>::iterator 23 #define mysets multiset<ll> 24 #define myits multiset<ll>::iterator 25 #define v30 (1<<30)-1 26 #define all(x) (x).begin(),(x).end() 27 #define maxs *s.rbegin() 28 #define lowbit(x) (x&(-x)) 29 #define mid ((a[k].r+a[k].l)>>1) 30 #define lson k<<1,l,mid 31 #define rson k<<1|1,mid+1,r 32 #define kl k<<1 33 #define kr k<<1|1 34 #define ispow(n) (n & (n - 1)) 35 using namespace std; 36 const ll N=1000005; 37 const ll mod = 1e9 + 7; 38 const ll de = 2e9 + 1; 39 inline ll read() { 40 ll s = 0, w = 1; 41 char ch = getchar(); 42 while (ch < '0' || ch>'9') { if (ch == '-')w = -1; ch = getchar(); } 43 while (ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar(); 44 return s * w; 45 } 46 void put1() { puts("YES"); } 47 void put2() { puts("NO"); } 48 void put3() { puts("-1"); } 49 ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); } 50 using namespace std; 51 52 const int manx = 2e5 + 5; 53 54 ll head[manx], d[manx], f[manx][21], lg[manx]; 55 ll k = 0; 56 struct node { 57 ll v, next; 58 }e[manx * 2]; 59 void add(ll u, ll v) { 60 e[++k].v = v; 61 e[k].next = head[u]; 62 head[u] = k; 63 } 64 void dfs(ll u, ll fa) { 65 d[u] = d[fa] + 1; 66 f[u][0] = fa; 67 for (int i = 1; i <= lg[d[u]]; i++) 68 f[u][i] = f[f[u][i - 1]][i - 1]; 69 for (int i = head[u]; i; i = e[i].next) 70 if (e[i].v != fa) 71 dfs(e[i].v, u); 72 } 73 ll lca(ll a, ll b) { 74 if (d[a] < d[b]) swap(a, b); 75 while (d[a] > d[b]) a = f[a][lg[d[a] - d[b]] - 1]; 76 if (a == b) return a; 77 for (int i = lg[d[a]] - 1; i >= 0; i--) 78 if (f[a][i] != f[b][i]) 79 a = f[a][i], b = f[b][i]; 80 return f[a][0]; 81 } 82 int red[200050],blue[200050]; 83 int main() 84 { 85 ll i, j, k; 86 ll n, m, t; 87 ll r, b,q; 88 cin >> n; 89 for (int i = 1; i < n; i++) { 90 ll u = read(), v = read(); 91 add(u, v); 92 add(v, u); 93 } 94 for (int i = 1; i <= n; i++) 95 lg[i] = lg[i - 1] + (1 << lg[i - 1] == i); 96 dfs(1, 0); 97 cin >> q; 98 while (q--) 99 { 100 cin >> r >> b; 101 cin >> red[1]; 102 int rlca = red[1]; 103 for (i = 2; i <= r; i++) 104 { 105 cin >> red[i]; 106 rlca = lca(rlca, red[i]); 107 } 108 cin >> blue[1]; 109 int blca = blue[1]; 110 for (i = 2; i <= b; i++) 111 { 112 cin >> blue[i]; 113 blca = lca(blca, blue[i]); 114 } 115 int zonglca = lca(rlca, blca); 116 if (rlca != zonglca && blca != zonglca) 117 { 118 cout << "YES" << endl; 119 } 120 else if (rlca == zonglca) 121 { 122 int flag = 0; 123 for ( i = 1; i <= r; i++) 124 { 125 if (lca(red[i], blca) == blca) 126 { 127 cout << "NO" << endl; 128 flag = 1; 129 break; 130 } 131 } 132 if (!flag) 133 cout << "YES" << endl; 134 } 135 else if (blca == zonglca) 136 { 137 int flag = 0; 138 for (i = 1; i <= b; i++) 139 { 140 if (lca(blue[i], rlca) == rlca) 141 { 142 cout << "NO" << endl; 143 flag = 1; 144 break; 145 } 146 } 147 if (!flag) 148 cout << "YES" << endl; 149 } 150 } 151 152 }
E - Third-Party Software - 2 Gym - 102215E
题意:求用最少的线段覆盖整个区间,并且输出你用的线段
思路:贪心,排序左端点从小到大,若左端点相同则取右端点从大到小排序,然后遍历即可。
献上代码
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<map> 5 #include<cstring> 6 using namespace std; 7 #define ll long long 8 const int N = 2e5+5; 9 const int mod = 1e9 + 7; 10 struct node { 11 ll l, r; 12 ll id; 13 }s[N]; 14 bool cmp(const node& a, const node& b) 15 { 16 if (a.l == b.l)return a.r > b.r; 17 return a.l < b.l; 18 } 19 vector<ll>G; 20 int main() 21 { 22 ll i, j, k; 23 ll n,m, t; 24 cin >> n >> m; 25 for (i = 0; i < n; i++) 26 { 27 cin >> s[i].l >> s[i].r; 28 s[i].id = i; 29 } 30 sort(s, s + n, cmp); 31 ll now = 1, ans = 0; 32 i = 0; 33 while (i <= n && now <= m) 34 { 35 ll maxn = 0; 36 k = 0; 37 while (i <= n && s[i].l <= now) 38 { 39 if (s[i].r > maxn) 40 { 41 maxn = s[i].r; 42 k = i; 43 } 44 i++; 45 } 46 if (maxn <= now - 1) 47 { 48 ans = -1; 49 break; 50 } 51 G.push_back(s[k].id+1); 52 now = maxn + 1; 53 ans++; 54 } 55 if (now <= m)//不能包括所有点 56 ans = -1; 57 if (ans == -1) 58 cout << "NO" << endl; 59 else 60 { 61 cout << "YES" << endl; 62 cout << ans << endl; 63 for (i = 0; i < ans; i++) 64 cout << G[i] << " "; 65 } 66 67 68 69 }
F - The Power of the Dark Side - 2 Gym - 102215J
题意:给你n个野蛮人(绝地武士)能力值a,b,c,两个武士决斗时谁有两个值大于对方谁就是胜者(a和a比,b和b比,c和c比,所有武士的三个值都不相同),现在可以交换任意武士的三个能力值位置,问有些可以击败其余所有武士。
思路:贪心排序能力,先将自己能力进行排序,然后将打败下限(即最小能力+1和次小能力+1)进行排序,再二分upper_bound属个数,再判断有没有自己揍自己就行。
献上代码(我提交的MV c++2017才不T)
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<map> 5 #include<cstring> 6 using namespace std; 7 #define ll long long 8 const int N = 5e5+25; 9 const int mod = 1e9 + 7; 10 ll s[N][3]; 11 ll sum[N]; 12 int i, j, k; 13 ll n,m, t; 14 vector<ll>v; 15 vector<int>ans; 16 int main() 17 { 18 19 scanf("%d", &n); 20 for (i = 1; i <= n; i++) 21 { 22 cin >> s[i][0] >> s[i][1] >> s[i][2]; 23 sum[i] = s[i][0] + s[i][1] + s[i][2]; 24 sort(s[i], s[i] + 3); 25 v.push_back(s[i][0] + s[i][1]+2);//注意,+2这里是次大被打败需要加一,最小被打败也要+1 26 } 27 sort(v.begin(), v.end()); 28 for (i = 1; i <= n; i++) 29 { 30 int k = upper_bound(v.begin(), v.end(), sum[i]) - v.begin(); 31 ll t = sum[i] - (s[i][0] + s[i][1] + 2); 32 if (t >= 0) 33 k--;//减去我自己打自己 34 ans.push_back(k); 35 } 36 for (i = 0; i < n; i++) 37 printf("%d ", ans[i]); 38 }
G - Bashar and the bad land (Hard) Gym - 102397E
题意:给你一个n个数和x,问最短的区间和大于等于x
思路:前缀和+尺取法,在1点先弄一个长度(假设为R)刚好区间和大于等于x,然后从R点向右移动,然后1点一直尺取收缩使得刚好大于等于x,详情看代码吧。
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<cstring> 5 using namespace std; 6 #define ll long long 7 const int N = 1000005; 8 const int mod = 1e9 + 7; 9 ll a[N],b[N],c[N]; 10 int main() 11 { 12 ll i, j, k; 13 ll n, m, t,x,sum=0; 14 cin >> n >> x; 15 for (i = 1; i <= n; i++) 16 { 17 cin >> a[i]; 18 sum += a[i]; 19 } 20 if (sum < x) 21 cout << -1 << endl; 22 else 23 { 24 a[0] = 0; 25 for (i = 1; i <= n; i++) 26 { 27 b[i] = b[i - 1] + a[i]; 28 } 29 /* for (i = 1; i <= n; i++) 30 { 31 cout << b[i] << " "; 32 }*/ 33 for (i = 1; i <= n; i++) 34 if (b[i] > x) 35 break; 36 // cout << endl << i << endl; 37 ll l = 1, r = i,ans=i,cnt=b[r]; 38 for(j=i;j<=n;j++) 39 { 40 cnt = b[j]-b[l-1]; 41 while (b[j] - b[l] >= x) 42 l++; 43 ans = min(ans, j - l + 1); 44 // cout << cnt << endl; 45 } 46 cout << ans << endl; 47 48 } 49 50 }
H - Deck Sorting Gym - 102215K
题意:给你只含RGB的字符串,从中抽出一个子序列,和剩下的子序列拼在一起,使得拼接后的字符串相同字符在一起。
思路:枚举6种全排列方式,比如RGB,先取全部R,G留下,然后最后一个R连接后面B,第一个G连接前面的B,若拼起来的长度不够原来的长度,则枚举下一种,直到没有符合输出NO。
代码
1 #include<iostream> 2 #include<algorithm> 3 #include<vector> 4 #include<map> 5 #include<cstring> 6 using namespace std; 7 #define ll long long 8 const int N = 5e5+25; 9 const int mod = 1e9 + 7; 10 char ju[6][3] = { 11 {'R','G','B'},{'R','B','G'}, 12 {'G','R','B'},{'G','B','R'}, 13 {'B','G','R'},{'B','R','G'} 14 }; 15 vector<char>s1; 16 vector<char>s2; 17 int main() 18 { 19 ll i, j, k; 20 string s; 21 ll n; 22 cin >> s; 23 n = s.size(); 24 int flag = 0; 25 for (i = 0; i < 6; i++) 26 { 27 ll sum1 = 0, sum2 = 0; 28 ll pos1 = 0, pos2 = 0; 29 for (j = 0; j < n; j++) 30 { 31 if (s[j] == ju[i][0]) 32 { 33 sum1++; 34 pos1 = j;//标记最后一个点 35 } 36 if (s[j] == ju[i][2]) 37 { 38 sum2++; 39 } 40 } 41 for (j = 0; j < n; j++) 42 { 43 if (s[j] == ju[i][2]) 44 { 45 pos2 = j;//标记第一个点 46 break; 47 } 48 } 49 for (j = 0; j < pos2; j++) 50 if (s[j] == ju[i][1]) 51 sum2++; 52 for (j = n - 1; j > pos1; j--) 53 if (s[j] == ju[i][1]) 54 sum1++; 55 if (sum1 + sum2 == n) 56 { 57 flag = 1; 58 break; 59 } 60 } 61 if (flag) 62 cout << "YES" << endl; 63 else 64 cout << "NO" << endl; 65 }