2020-06-01 — 习题训练四题解
https://vjudge.net/contest/376443#overview
A-Dreamoon and Ranking Collection
给x个补丁,从第一个开始补, 遇见漏洞,补丁就少一个, 补完之后,从一到最大的没毛病的数是多少
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5 + 10; template <typename T> inline void read(T &ret) { char c; int sgn; if (c = getchar(), c == EOF) return ; while (c != '-' && (c < '0' || c > '9')) c = getchar(); sgn = (c == '-') ? -1:1; ret = (c == '-') ? 0:(c - '0'); while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0'); ret *= sgn; return ; } void solve(){ int n, x, v; read(n), read(x); vector<int> a(n+1); vector<bool> s(300); for(int i = 1;i <= n; ++ i){ read(a[i]); s[a[i]] = true; } for(int i = 1;i <= 300; ++ i){ if(!s[i] && x > 0){ x --; continue; } if(!s[i] && !x){ v = i - 1; break; } } printf("%d\n", v); } int main() { ios_base::sync_with_stdio(false); int t; read(t); while(t--) solve(); }
B - Dreamoon Likes Permutations
给一个序列,切开,使得切开后的两个序列中的数字为从1到该序列的长度(数字不能重复),求所有满足题意的切法
用一个数组标记前面满足条件的序列,另一个标记后面满足条件的序列,最后输出。(借鉴某大佬)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5 + 10; template <typename T> inline void read(T &ret) { char c; int sgn; if (c = getchar(), c == EOF) return ; while (c != '-' && (c < '0' || c > '9')) c = getchar(); sgn = (c == '-') ? -1:1; ret = (c == '-') ? 0:(c - '0'); while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0'); ret *= sgn; return ; } void solve(){ int n, cnt = 0; read(n); // int a[n+1], cntl[n+1], cntr[n+1]; // bool l[n+1], r[n+1]; vector<int> a(n+1), cntl(n+1), cntr(n+1); vector<bool> l(n+1), r(n+1); for(int i = 1;i <= n; ++ i) read(a[i]); int x = 1; for(int i = 1;i <= n; ++ i){ cntl[a[i]] ++; if(cntl[a[i]] >= 2) break; while(cntl[x] == 1 && x <= i) x ++; // 若是到不了i ,从x 到i 之间有0,也就不合适. if(x - 1 == i) l[i] = true; } x = 1; for(int i = n;i >= 1; -- i){ cntr[a[i]] ++; if(cntr[a[i]] >= 2) break; while(cntr[x] == 1 && x <= n - i + 1) x ++; if(x - 1 == n - i + 1) r[i] = true; } for(int i = 1;i <= n-1; ++ i) if(l[i] && r[i+1]) cnt ++; printf("%d\n", cnt); if(cnt) for(int i = 1;i < n; ++ i) if(l[i] && r[i + 1]) printf("%d %d\n", i, n - i); } int main() { ios_base::sync_with_stdio(false); int t; read(t); while(t--) solve(); }
C - Exercising Walk
大概分类讨论吧
#include<iostream> using namespace std; int t, a, b, c, d, x, y, xl, xr, yl,yr; int main() { cin >> t; while (t--) { int flag = 0; cin >> a >> b >> c >> d; cin >> x >> y >> xl >> yl >> xr >> yr; //特判两种特殊情况 if (xl == xr && (a >= 1 || b >= 1)) flag = 0; else if(yl == yr && (c >= 1 || d >= 1)) flag = 0; //判断是否在边界内 else { x = x + (b - a); y = y + (d - c); if (x >= xl && x <= xr && y >= yl && y <= yr) flag = 1; } if (flag) cout << "YES" << endl; else cout << "NO" << endl; } return 0; }
D-Composite Coloring
题意:给定n个合数,用m(<= 11) 种颜色染色,当两个数字有相同的公约数时可以染同一种颜色
找出前11个质数,若公约数相同,染同样颜色,不同就换颜色。题目给出 m<= 11 即可。而a < 1000, 所以不会 出现 37 * 43 这样的数, 也就是说,前11个质数够用(第十一个质数为31) (借鉴某大佬)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5 + 10; template <typename T> inline void read(T &ret) { char c; int sgn; if (c = getchar(), c == EOF) return ; while (c != '-' && (c < '0' || c > '9')) c = getchar(); sgn = (c == '-') ? -1:1; ret = (c == '-') ? 0:(c - '0'); while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0'); ret *= sgn; return ; } int gcd(int a, int b) { while(b != 0) { int r = b; b = a % b; a = r; } return a; } void solve(){ int prime[11] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31}; int n, cnt = 0; read(n); vector<int> a(n+1), ans(n+1); map<int, int> dis; for(int i = 1;i <= n; ++ i) read(a[i]); for(int i = 1;i <= n; ++ i){ for(int j = 0;j < 11; ++ j){ if(a[i] % prime[j] == 0){ if(!dis[prime[j]]) dis[prime[j]] = ++ cnt; ans[i] = dis[prime[j]]; break; } } } printf("%d\n", cnt); for(int i = 1;i <= n; ++ i) printf("%d ",ans[i]); puts(""); } int main() { ios_base::sync_with_stdio(false); int t; read(t); while(t--) solve(); }
E - K-th Beautiful String
给出字符串aaaaaaaabb (类似) , 经过排列变换后,找出第 k 大的字符串(字典序)
n - 2 个a: a a a a ... a a a , 两个b 插进去;
第一个b 的位置 b = n - 1 : a a a a ..... a a a b k的可能取值为 1;
b 的位置 b = n - 2 : a a a a ..... a a b a k : 2 3 // 与不同的k 对应的另一个 b的位置应该能直接看出来
b = n - 3 :a a a a ..... a b a a k: 4 5 6
。 k : 7 8 9 10
。
。
b = 0 : b a a a .... a a a a k : i * ( i - 1) / 2 + 1 ....... ; (就当 i 从 1 开始自增好了)
现在可以回答第k 个是哪个了, 首先找到 k 所在的行,就可以找到第一个b的位置了,然后用 k 减去 所在行的第一个数,就是另一个b与n-1的距离,两个b的位置就找到了
//好麻烦,附个简洁的题解
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5 + 10; template <typename T> inline void read(T &ret) { char c; int sgn; if (c = getchar(), c == EOF) return ; while (c != '-' && (c < '0' || c > '9')) c = getchar(); sgn = (c == '-') ? -1:1; ret = (c == '-') ? 0:(c - '0'); while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0'); ret *= sgn; return ; }void solve(){ int n, x; read(n), read(x); vector<char> a(n+1); for(int i = 1;i <= n - 2; ++ i) a[i] = 'a'; int b1, b2; for(int i = 1;i <= n; ++ i){ if((ll)i *(i - 1) / 2 + 1 > x){ b1 = i-1; b1 = n - 1 - b1; b2 = x - ((ll) (i-1) * (i - 2) / 2 + 1); b2 = n - 2 - b2; break; } } for(int i = 0;i <= n-2; ++ i){ if(i) putchar(a[i]); if(b1 == i) putchar('b'); if(b2 == i) putchar('b'); } puts(""); } int main() { ios_base::sync_with_stdio(false); int t; read(t); while(t--) solve(); }
F - Carousel
题意: 闭合圈中,相邻的不同元素要涂成不同颜色,问最多需要多少种颜色可涂满,并写出涂法
闭合圈中,有一种元素时,全输出1
有两种元素时,循环输出1, 2;
有三种元素时, 如果 n 为偶数, 循环输出1, 2;
如果n 为奇数, 查找有无相邻相等的元素(闭合圈),如果有那就可以看成偶数列,第一次相等时, 相等的两个元素输出一样的数,这样就又可以看成偶数列了;
如果没有相邻相等的,那就循环输出1, 2最后一个元素输出3
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5 + 10; template <typename T> inline void read(T &ret) { char c; int sgn; if (c = getchar(), c == EOF) return ; while (c != '-' && (c < '0' || c > '9')) c = getchar(); sgn = (c == '-') ? -1:1; ret = (c == '-') ? 0:(c - '0'); while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0'); ret *= sgn; return ; } void solve(){ int n, flag = 0; read(n); vector<int> a(n+1), ans(n+1); set<int> st; for(int i = 1;i <= n; ++ i){ read(a[i]); if(i > 1 && a[i] == a[i-1]) flag ++; if(i == n && a[i] == a[1]) flag ++; } // cout << "flag : " << flag << endl; if(flag == n){ puts("1"); for(int i = 1;i <= n; ++ i) printf("1 "); puts(""); return ; } if(n % 2 == 0){ puts("2"); for(int i = 1;i <= n / 2; ++ i){ printf("1 2 "); } puts(""); return ; } else{ if(flag == 0){ puts("3"); for(int i = 1;i <= n / 2; ++ i) printf("1 2 "); puts("3"); return ; } else{ flag = 1; puts("2"); int cnt = 1; for(int i = 1;i <= n; ++ i){ if(cnt > 2) cnt = 1; if(i > 1 && a[i] == a[i-1] && flag){ //补一次就行 ans[i] = ans[i-1]; cnt = ans[i-1]; flag = 0; } else ans[i] = cnt; cnt ++; printf("%d ",ans[i]); } puts(""); } } } int main() { ios_base::sync_with_stdio(false); int t; read(t); while(t--) solve(); }