Codeforces Round #552 (Div. 3)
本场题目不难,暴力模拟大法好。A~E:模拟+暴力(有些是贪心);F:留坑待填;G:埃氏筛+贪心。
A、Restoring Three Numbers
思路:简单数学。
AC代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <iostream> 6 #include <algorithm> 7 #include <iomanip> 8 #include <complex> 9 #include <string> 10 #include <vector> 11 #include <set> 12 #include <map> 13 #include <list> 14 #include <deque> 15 #include <queue> 16 #include <stack> 17 #include <bitset> 18 using namespace std; 19 typedef long long LL; 20 typedef unsigned long long ULL; 21 const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 上右下左 22 const int mx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; // 马可走的八个方向 23 const int my[8] = {-2, -1, 1, 2, 2, 1, -1, -2}; 24 const double eps = 1e-6; 25 const double PI = acos(-1.0); 26 const int maxn = 1e5+5; 27 const int inf = 0x3f3f3f3f; 28 29 30 LL x[5], a, b, c; 31 32 int main() { 33 while(cin >> x[1] >> x[2] >> x[3] >> x[4]) { 34 sort(x + 1, x + 5); 35 b = (x[1] - x[2] + x[3]) / 2; 36 c = x[3] - b; 37 a = x[4] - b - c; 38 cout << a << ' ' << b << ' ' << c << endl; 39 } 40 return 0; 41 }
B、Make Them Equal
思路:暴力+模拟。只需枚举最终的数组变成的数字(1~100)即可。
AC代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <iostream> 6 #include <algorithm> 7 #include <iomanip> 8 #include <complex> 9 #include <string> 10 #include <vector> 11 #include <set> 12 #include <map> 13 #include <list> 14 #include <deque> 15 #include <queue> 16 #include <stack> 17 #include <bitset> 18 using namespace std; 19 typedef long long LL; 20 typedef unsigned long long ULL; 21 const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 上右下左 22 const int mx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; // 马可走的八个方向 23 const int my[8] = {-2, -1, 1, 2, 2, 1, -1, -2}; 24 const double eps = 1e-6; 25 const double PI = acos(-1.0); 26 const int maxn = 105; 27 const int inf = 0x3f3f3f3f; 28 29 30 int n, ans, now, cha, a[maxn]; 31 bool flag; 32 33 int main() { 34 while(~scanf("%d", &n)) { 35 for(int i = 0; i < n; ++i) scanf("%d", &a[i]); 36 sort(a, a + n); 37 ans = inf; 38 for(int j = 0; j <= 100; ++j) { // 枚举最终数组中所有的元素变为j 39 now = 0, cha = 0; // 注意:cha的初始值为0,因为1~n每个数都可能与j相同 40 for(int k = 0; k < n; ++k) // 找到第一个与j不同的数求差的绝对值cha 41 if(a[k] != j) {cha = abs(a[k] - j); break;} 42 for(int k = 0; k < n; ++k) { // 模拟即可 43 if(a[k] < j) { 44 if(a[k] + cha == j) ++now; 45 else break; 46 } 47 else if(a[k] > j) { 48 if(a[k] - cha == j) ++now; 49 else break; 50 } 51 else if(a[k] == j) ++now; 52 } 53 if(now == n) ans = min(ans, cha); 54 } 55 if(ans == inf) puts("-1"); 56 else printf("%d\n", ans); 57 } 58 return 0; 59 }
C、Gourmet Cat
思路:数学+暴力。由题易得一周内猫吃肉的种类依次为 a、b、c、a、c、b、a。若 $ a \geq 3 \land b \geq 2 \land c \geq 2 $,则先算出轮数;(否则)剩下的枚举每一天作为起点,简单暴力模拟即可。
AC代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <iostream> 6 #include <algorithm> 7 #include <iomanip> 8 #include <complex> 9 #include <string> 10 #include <vector> 11 #include <set> 12 #include <map> 13 #include <list> 14 #include <deque> 15 #include <queue> 16 #include <stack> 17 #include <bitset> 18 using namespace std; 19 typedef long long LL; 20 typedef unsigned long long ULL; 21 const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 上右下左 22 const int mx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; // 马可走的八个方向 23 const int my[8] = {-2, -1, 1, 2, 2, 1, -1, -2}; 24 const double eps = 1e-6; 25 const double PI = acos(-1.0); 26 const int maxn = 105; 27 const int inf = 0x3f3f3f3f; 28 29 int a, b, c, d, ans, now1, now2, k, dir0[7] = {0, 1, 2, 0, 2, 1, 0}, cnt[3], cnt1[3]; 30 31 int main() { 32 while(cin >> a>> b >> c) { 33 ans = 0; 34 memset(cnt, 0, sizeof(cnt)); 35 if(a >= 3 && b >= 2 && c >= 2) { 36 k = min(a / 3, min(b / 2, c / 2)); 37 a -= 3 * k, b -= 2 * k, c -= 2 * k; 38 ans = 7 * k; 39 } 40 cnt[0] = a, cnt[1] = b, cnt[2] = c, now2 = 0; 41 for(int i = 0; i < 7; ++i) { // 枚举每一天作为起点 42 cnt1[0] = cnt[0], cnt1[1] = cnt[1], cnt1[2] = cnt[2], now1 = 0; 43 for(int j = i; ; ++j) { // 模拟 44 if(cnt1[dir0[j % 7]] > 0) --cnt1[dir0[j % 7]], ++now1; 45 else break; 46 } 47 now2 = max(now1, now2); 48 } 49 cout << ans + now2 << endl; 50 } 51 return 0; 52 }
D、Walking Robot
思路:简单贪心+模拟。详细思路见代码注释。
AC代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <iostream> 6 #include <algorithm> 7 #include <iomanip> 8 #include <complex> 9 #include <string> 10 #include <vector> 11 #include <set> 12 #include <map> 13 #include <list> 14 #include <deque> 15 #include <queue> 16 #include <stack> 17 #include <bitset> 18 using namespace std; 19 typedef long long LL; 20 typedef unsigned long long ULL; 21 const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 上右下左 22 const int mx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; // 马可走的八个方向 23 const int my[8] = {-2, -1, 1, 2, 2, 1, -1, -2}; 24 const double eps = 1e-6; 25 const double PI = acos(-1.0); 26 const int maxn = 2e5+5; 27 const int inf = 0x3f3f3f3f; 28 29 int n, b, a, x, y, ans, s[maxn]; 30 31 int main() { 32 while(cin >> n >> x >> y) { 33 ans = 0; b = x, a = y; 34 for(int i = 0; i < n; ++i) cin >> s[i]; 35 for(int i = 0; i < n; ++i) { 36 if(s[i]) { // 若被光照 37 if(b) { // 先考虑1个b转换成1个a 38 if(a + 1 <= y) --b, ++a, ++ans; // 最大不超过y 39 else if(a) --a, ++ans; // 不能转,则先减去a 40 else if(b) --b, ++ans; // a为0不能继续减,才看b是否剩余 41 else break; 42 } 43 else if(a) --a, ++ans; // 没有b,则只能减去a 44 else break; // 没法减则退出 45 }else { // 没有被光照,不能转 46 if(a) --a, ++ans; // 先考虑a 47 else if(b) --b, ++ans; // a不能减,再考虑b,因为b的作用遇到光时能产生一个a 48 else break; // 没法减则退出 49 } 50 } 51 cout << ans << endl; 52 } 53 return 0; 54 }
E、Two Teams
思路:题意很简单:每次找当前队列中技能最大的学生,向左向右分别连续选择k个学生作为自己的队员。①暴力险过。②换种思路:用大根堆维护当前序列的最大值,同时标记每个元素分别向前、向后走的第一个位置,剩下的暴力模拟即可。
AC代码一:暴力解。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <iostream> 6 #include <algorithm> 7 #include <iomanip> 8 #include <complex> 9 #include <string> 10 #include <vector> 11 #include <set> 12 #include <map> 13 #include <list> 14 #include <deque> 15 #include <queue> 16 #include <stack> 17 #include <bitset> 18 using namespace std; 19 typedef long long LL; 20 typedef unsigned long long ULL; 21 const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 上右下左 22 const int mx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; // 马可走的八个方向 23 const int my[8] = {-2, -1, 1, 2, 2, 1, -1, -2}; 24 const double eps = 1e-6; 25 const double PI = acos(-1.0); 26 const int maxn = 2e5+5; 27 const int inf = 0x3f3f3f3f; 28 29 int n, k, a, ans[maxn], siz, now, cnt, pos, mp[maxn], lt, rt; 30 vector<int> vec; 31 set<int> stl; 32 set<int>::iterator it; 33 34 int main() { 35 while(~scanf("%d%d", &n, &k)) { 36 memset(ans, 0, sizeof(ans)); 37 memset(mp, 0, sizeof(mp)); 38 vec.clear(); 39 stl.clear(); 40 cnt = 0; 41 for(int i = 0; i < n; ++i) { 42 scanf("%d", &a); 43 vec.push_back(a); 44 mp[a] = i; 45 stl.insert(a); 46 } 47 while((siz = stl.size()) != 0) { 48 it = stl.end(); 49 --it; 50 ++cnt; 51 if(cnt & 1) now = 1; 52 else now = 2; 53 pos = find(vec.begin(), vec.end(), *it) - vec.begin(); 54 lt = max(0, pos - k), rt = min(siz - 1, pos + k); 55 for(int i = lt; i <= rt; ++i) { 56 ans[mp[vec[i]]] = now; 57 stl.erase(vec[i]); 58 } 59 vec.erase(vec.begin() + lt, vec.begin() + rt + 1); 60 } 61 for(int i = 0; i < n; ++i) printf("%d", ans[i]); 62 puts(""); 63 } 64 return 0; 65 }
AC代码二:优化解。
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <iostream> 6 #include <algorithm> 7 #include <iomanip> 8 #include <complex> 9 #include <string> 10 #include <vector> 11 #include <set> 12 #include <map> 13 #include <list> 14 #include <deque> 15 #include <queue> 16 #include <stack> 17 #include <bitset> 18 using namespace std; 19 typedef long long LL; 20 typedef unsigned long long ULL; 21 const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 上右下左 22 const int mx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; // 马可走的八个方向 23 const int my[8] = {-2, -1, 1, 2, 2, 1, -1, -2}; 24 const double eps = 1e-6; 25 const double PI = acos(-1.0); 26 const int maxn = 2e5+5; 27 const int inf = 0x3f3f3f3f; 28 29 int n, k, a, now1, now2, flag, p1, p2, num, ans[maxn], nex[maxn], per[maxn]; 30 31 priority_queue<pair<int, int> > que; 32 bool vis[maxn]; 33 34 35 int main() { 36 while(~scanf("%d%d", &n, &k)) { 37 while(!que.empty()) que.pop(); 38 memset(ans, 0, sizeof(ans)); 39 memset(per, 0, sizeof(per)); 40 memset(nex, 0, sizeof(nex)); 41 flag = 1; 42 memset(vis, false, sizeof(vis)); 43 for(int i = 1; i <= n; ++i) { 44 scanf("%d", &a); 45 que.push(make_pair(a, i)); 46 per[i] = i - 1; 47 nex[i] = i + 1; 48 } 49 while(!que.empty()) { 50 now1 = que.top().first, now2 = que.top().second, que.pop(); 51 if(vis[now2]) continue; 52 vis[now2] = true; 53 flag = !flag; 54 p1 = per[now2], p2 = nex[now2], ans[now2] = flag + 1; 55 num = k; 56 while(num > 0 && p1 > 0) vis[p1] = true, ans[p1] = flag + 1, --num, p1 = per[p1]; 57 num = k; 58 while(num > 0 && p2 <= n) vis[p2] = true, ans[p2] = flag + 1, --num, p2 = nex[p2]; 59 per[p2] = p1, nex[p1] = p2; 60 } 61 for(int i = 1; i <= n; ++i) printf("%d", ans[i]); 62 puts(""); 63 } 64 return 0; 65 }
G、Minimum Possible LCM
思路:埃氏筛+贪心。题意就是找出2个数使其最小公倍数最小。题目虽然给的时限是4s,但我们要换种优雅的方式来暴力,即来枚举每一个gcd(求lcm需要先求出2个数的gcd)。借用埃氏筛思想,公约数为gcd的步长增长,不难想到,头2次出现的这2个数的最小公倍数一定为gcd时的最小lcm,那么我们就可以用 $O(nlog^n)$的时间复杂度,大约是 $1.6 \times 10^8 $(1s的极限是$ 1.0 \times 10^8 $)即用1s多就可以过掉此题!
AC代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <iostream> 6 #include <algorithm> 7 #include <iomanip> 8 #include <complex> 9 #include <string> 10 #include <vector> 11 #include <set> 12 #include <map> 13 #include <list> 14 #include <deque> 15 #include <queue> 16 #include <stack> 17 #include <bitset> 18 using namespace std; 19 typedef long long LL; 20 typedef unsigned long long ULL; 21 const int dir[4][2] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}}; // 上右下左 22 const int mx[8] = {-1, -2, -2, -1, 1, 2, 2, 1}; // 马可走的八个方向 23 const int my[8] = {-2, -1, 1, 2, 2, 1, -1, -2}; 24 const double eps = 1e-6; 25 const double PI = acos(-1.0); 26 const LL maxn = 1e7+5; 27 const LL inf = 1LL << 62; 28 29 30 int n, num, p1, p2, per1, per2, siz; 31 LL ans, now0, now1, now2, a; 32 33 bool vis[maxn]; 34 35 vector<int> vec[maxn]; 36 37 38 int main() { 39 while(~scanf("%d", &n)) { 40 ans = inf; 41 per1 = per2 = 0; 42 for(LL i = 0LL; i < maxn; ++i) vec[i].clear(); 43 memset(vis, false, sizeof(vis)); 44 for(int i = 1; i <= n; ++i) { 45 scanf("%lld", &a); 46 vec[a].push_back(i); 47 vis[a] = true; // 标记出现的元素 48 } 49 for(LL i = 1LL; i < maxn; ++i) { 50 num = 0; 51 for(LL j = i; j < maxn && num < 2; j += i) { 52 if(!vis[j]) continue; 53 if(num == 0) { // 第一次出现 54 siz = vec[j].size(); 55 if(siz == 1) { 56 ++num; 57 p1 = vec[j][0]; 58 now1 = j; 59 } 60 else { 61 num += 2; // 头2个 62 p1 = vec[j][0], p2 = vec[j][1]; 63 now1 = j, now2 = j; 64 } 65 }else { // 第二次出现 66 ++num; 67 now2 = j; 68 p2 = vec[j][0]; 69 } 70 } 71 if(num == 2) { 72 now0 = now1 / i * now2; 73 if(ans > now0) { 74 ans = now0; 75 per1 = p1, per2 = p2; 76 } 77 } 78 } 79 if(per1 > per2) swap(per1, per2); 80 printf("%d %d\n", per1, per2); 81 } 82 return 0; 83 }