啦啦啦,最近比较懒所以之前的坑没有填完,也没怎么写新的博客
5月份就要来了,ytz也要开始勤奋的码代码~(≧▽≦)/~啦啦啦
Codeforces Round #410 (Div. 2)
A.Mike and palindrome
题目已经很良心地加粗了重点了,like this
He wants to change exactly one character from the string so that the resulting one is a palindrome.
所以我们需要注意如果原串本身就是回文串的话
那么长度为奇数,中间字符可以随便改,符合题目要求,即更改正好一个字符后仍为回文串
长度为偶数显然没得改,不满足题目要求所以是要输出NO的
#include <bits/stdc++.h> #define rep(i, j, k) for(int i = j;i <= k;i ++) #define rev(i, j, k) for(int i = j;i >= k;i --) using namespace std; int main() { ios::sync_with_stdio(false); int n = 0; string s; cin >> s; rep(i, 0, s.size() - 1) n += (s[i] != s[s.size() - 1 - i]); if(n == 2 || (n == 0 && (s.size() & 1))) puts("YES"); else puts("NO"); return 0; }
B.Mike and strings
题目不是很难,直接枚举目标串即可
假设string中find函数效率为O(n^2)的话,(实际上大概就是这个效率
效率约为O(n^4),n很小可以接受
#include <bits/stdc++.h> #define rep(i, j, k) for(int i = j;i <= k;i ++) #define rev(i, j, k) for(int i = j;i >= k;i --) using namespace std; int n, m, k, a[100]; string s[100]; bool work() { string t; rep(i, 1, n) { k = 0; rep(j, 1, n) { t = s[j] + s[j]; if(t.find(s[i]) == -1) return 0; k += t.find(s[i]); } m = min(m, k); } return 1; } int main() { ios::sync_with_stdio(false); cin >> n, m = 666666; rep(i, 1, n) cin >> s[i]; if(work()) cout << m; else puts("-1"); return 0; }
另外聊一个很有意思的错误,是我第一次意识流出来的O(n^3)做法
可以参考一下错误之处,看一下你能不能看出来错误
其实是描述有些麻烦
错误代码:
#include <bits/stdc++.h> #define rep(i, j, k) for(int i = j;i <= k;i ++) #define rev(i, j, k) for(int i = j;i >= k;i --) using namespace std; int n, m, k, a[100]; string s[100]; bool pre() { rep(i, 2, n) { s[i] += s[i]; a[i] = s[i].find(s[1]); if(a[i] == -1) return 0; m += a[i]; } return 1; } int main() { ios::sync_with_stdio(false); cin >> n; rep(i, 1, n) cin >> s[i]; if(pre()) { rep(i, 1, s[1].size() - 1) { k = i; rep(j, 2, n) { a[j] ++; if(a[j] >= s[1].size()) a[j] -= s[1].size(); k += a[j]; } m = min(m, k); } cout << m; } else puts("-1"); return 0; }
Wrong answer on test 94:
4 abcabcabc bcabcabca cabcabcab cabcabcab
4
3
C.Mike and gcd problem
首先我们可以先求gcd(ai),若gcd(ai) != 1,那么不必操作
否则呢,若最终可以变成beautiful,那么gcd一定是2
这个结论我们由操作的变化过程可以显然得到
delete numbers ai, ai + 1 and put numbers ai - ai + 1, ai + ai + 1 in their place instead
然后我们考虑变化,相邻两偶不必操作,相邻两奇变化一次得两偶
相邻一奇一偶变换一次得到两奇,再变一次即可...
最终我们发现无论如何都可以变beautiful的
#include <bits/stdc++.h> #define rep(i, j, k) for(int i = j;i <= k;i ++) #define rev(i, j, k) for(int i = j;i >= k;i --) using namespace std; int gcd(int x, int y) { return y ? gcd(y, x % y) : x; } int n, a[100010]; int main() { ios::sync_with_stdio(false); int k = 0; cin >> n; rep(i, 1, n) cin >> a[i], k = gcd(a[i], k); if(k != 1) puts("YES 0"); else { int st, en, d, i = 1, ans = 0; while(i <= n) { while(i <= n && !(a[i] & 1)) i ++;st = i; while(i <= n && (a[i] & 1)) i ++;en = i; d = en - st; if(d & 1) ans += (d >> 1) + 2; else ans += d >> 1; } cout << "YES " << ans; } return 0; }
D.Mike and distribution
题意很好理解...看完题解发现这是个很有意思的思维题
但在此之前我们先来看一个非常玄学而又大胆的做法!没错!random_shuffle!
竟然没有T掉...有没有人来证明时间复杂度的期望不会超时啊...
#include <bits/stdc++.h> #define rep(i, j, k) for(int i = j;i <= k;i ++) #define rev(i, j, k) for(int i = j;i >= k;i --) using namespace std; typedef long long ll; const int maxn = 100010; int n, a[maxn], b[maxn], c[maxn]; ll s1, s2, sa, sb; int main() { ios::sync_with_stdio(false); cin >> n; rep(i, 1, n) c[i] = i; rep(i, 1, n) cin >> a[i], sa += a[i]; rep(i, 1, n) cin >> b[i], sb += b[i]; while(1) { s1 = s2 = 0; random_shuffle(c + 1, c + n + 1); rep(i, 1, n / 2 + 1) s1 += a[c[i]], s2 += b[c[i]]; if(s1 * 2 > sa && s2 * 2 > sb) { cout << n / 2 + 1 << endl; rep(i, 1, n / 2 + 1) cout << c[i] << " "; return 0; } } return 0; }
而实际的高效正解
#include <bits/stdc++.h> #define rep(i, j, k) for(int i = j;i <= k;i ++) #define rev(i, j, k) for(int i = j;i >= k;i --) using namespace std; typedef long long ll; const int maxn = 100010; int n, a[maxn], b[maxn], c[maxn]; ll s1, s2, sa, sb; bool cmp(int x, int y) { return a[x] > a[y]; } int main() { ios::sync_with_stdio(false); cin >> n; rep(i, 1, n) c[i] = i; rep(i, 1, n) cin >> a[i], sa += a[i]; rep(i, 1, n) cin >> b[i], sb += b[i]; sort(c + 1, c + n + 1, cmp); cout << n / 2 + 1 << endl << c[1]; for(int i = 2;i <= n;i += 2) cout << " " << (b[c[i]] >= b[c[i + 1]] ? c[i] : c[i + 1]); return 0; }
我们在看懂简短代码的基础上来讨论其正确性
首先可以看到B数组中选出来的数的正确性是显然的,即其和×2>sum(B)很显然
那么考虑对A的最坏情况,i 和 i+1 中均选择了后一个比较小的 i+1
那么如何证明此时A中选出来的数之和×2一定 > sum(A)呢
我们注意到我们首先选择了c[1],即A中最大元素
那么一定有A[c[1]] > A[c[2]] - A[c[3]] + A[c[4]] - A[c[5]] ...
移项即可发现其正确性!
E.Mike and code of a permutation
还没做
外传:
学习安装了linux,安装的是deepin,界面果然美观,但是居然自带steam???
时隔半年,宿舍三人重新想起了宿舍wifi密码?感人!
软件商店的一大堆编程开发软件似乎打开新世界大门!技术真好玩!
忘记拿充电线所以玩到电脑没电才睡觉!年轻人不修仙难道浪费时间睡觉吗?