A. Sakurako's Exam
每次给两个数,第一个数表示序列中1的个数,第二个数表示序列中2的个数;在1和2前面加上+或者-,判断是否可以让整个序列的加减结果为0
只有1或只有2的情况,个数必须为偶数
有1有2的情况,根据2的奇偶情况进一步讨论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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> using namespace std;#define int long long void solve () { int a, b; cin >> a >> b; if (!b) { if (a % 2 == 0 ) cout << "YES" << '\n' ; else cout << "NO" << '\n' ; return ; } if (!a) { if (b % 2 == 0 ) cout << "YES" << '\n' ; else cout << "NO" << '\n' ; return ; } if (b % 2 ) { if (a % 2 == 0 ) cout << "YES" << '\n' ; else cout << "NO" << '\n' ; return ; } else { if (a % 2 == 0 ) cout << "YES" << '\n' ; else cout << "NO" << '\n' ; return ; } } signed main () { int t; cin >> t; while (t--) { solve (); } return 0 ; }
B. Square or Not
判断一个字符串转换成的矩形,能否是边界全为1内部全为0的正方形
判断能否是正方形
转换成矩阵,遍历即可
注意边长小于等于2的矩阵的特殊性,没有内部
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 #include <iostream> #include <string> #include <cmath> using namespace std;#define int long long const int N = 1e3 ;int g[N][N];void solve () { int n; cin >> n; string s; cin >> s; int e = sqrt (n); if (e * e != n) { cout << "No" << '\n' ; return ; } if (e <= 2 ) { if (s.find ('0' ) == string::npos) cout << "Yes" << '\n' ; else cout << "No" << '\n' ; return ; } else { for (int i = 0 ; i < n; i++) { g[i / e][i % e] = s[i] - '0' ; } for (int i = 0 ; i < e; i++) { for (int j = 0 ; j < e; j++) { if (i == 0 || j == 0 || i == e - 1 || j == e - 1 ) { if (g[i][j] != 1 ) { cout << "No" << '\n' ; return ; } } else { if (g[i][j] != 0 ) { cout << "No" << '\n' ; return ; } } } } cout << "Yes" << '\n' ; } } signed main () { int t; cin >> t; while (t--) { solve (); } return 0 ; }
C. Longest Good Array
给定两个数,要求在这两个数间插入最多的数得到一个序列,并且满足该序列单调递增并且元素之间的间隔不断增大,求整个序列的个数
利用二分,要数尽可能的多,那么间隔要尽可能的小,是从1开始的以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 28 29 30 31 #include <cmath> #include <iostream> using namespace std;#define int long long void solve () { int x, y; cin >> x >> y; int gap = y - x; int ans = 0 ; int l = 1 , r = sqrt (2 * gap), mid; while (l < r && l + 1 != r) { mid = l + r >> 1 ; if ((mid + 1 ) * mid / 2 <= gap) l = mid; else r = mid - 1 ; } if ((l + 1 ) * l / 2 <= gap) ans = max (ans, l + 1 ); if ((r + 1 ) * r / 2 <= gap) ans = max (ans, r + 1 ); cout << ans << '\n' ; } signed main () { int t; cin >> t; while (t--) { solve (); } return 0 ; }
D. Sakurako's Hobby
给定一个数组,根据数组的下标和数组的值进行不断递推,每个数都有黑白两种颜色,问\(1\sim
n\) 每个数可以到达的颜色为黑色的数的个数
利用并查集,将能到达的放在一个集合
设置一个数组用来记录每个集合中颜色为黑色的数的个数
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 #include <iostream> using namespace std;#define int long long const int N = 2e5 + 10 ;int s[N], c[N], p[N],ct[N];int find (int x) { if (x != p[x]) p[x] = find (p[x]); return p[x]; } void merge (int x, int y) { p[find (x)] = find (y); } void solve () { int n; cin >> n; bool st[N] = {}; for (int i = 1 ; i <= n; i++) p[i] = i; for (int i = 1 ; i <= n; i++) cin >> s[i]; string color; cin >> color; for (int i = 1 ; i <= n; i++) c[i] = color[i - 1 ] - '0' , ct[i] = 1 - c[i]; for (int i = 1 ; i <= n; i++) { if (!st[i]) { st[i] = true ; int j = s[i]; while (j != i) { merge (j, i); st[j] = true ; ct[find (j)] += 1 - c[j]; j = s[j]; } } } for (int i = 1 ; i <= n; i++) cout << ct[find (i)] << " " ; cout << '\n' ; } signed main () { int t; cin >> t; while (t--) { solve (); } return 0 ; }
E. Alternating String
对一个序列有两个操作方式:删除一个字母(最多进行一次该操作);改变一个字母。让序列最终变成偶数个数且奇数位和偶数位上的字母分别相同
分序列数本来是偶数和奇数进行讨论
在序列是奇数的情况下要进行第一个操作,而删除一个数会改变后面序列的奇偶,于是\(\color{red}{我们从后往前枚举删除的数}\) ,这样在枚举删除前面的字母的时候后面的字母的奇偶已经是改变的了
本题应用了上篇Codeforces-971-G对数据类似的处理方法
\(\color{red}{补充:}\) 为什么erase要用find?因为如果是删除数,而不是删除位置,那么multiset中的所有等于该数的数都会被删除
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 80 81 #include <iostream> #include <set> #include <map> using namespace std;#define int long long void solve () { int n; cin >> n; string s; cin >> s; if (n == 1 || n == 3 ) { cout << 1 << '\n' ; return ; } if (n == 2 ) { cout << 0 << '\n' ; return ; } multiset<int > e, o; map<int , int > me, mo; for (int i = 0 ; i < n; i += 2 ) { if (e.count (me[s[i] - 'a' ])) e.erase (e.find (me[s[i] - 'a' ])); me[s[i] - 'a' ]++; e.insert (me[s[i] - 'a' ]); } for (int i = 1 ; i < n; i += 2 ) { if (o.count (mo[s[i] - 'a' ])) o.erase (o.find (mo[s[i] - 'a' ])); mo[s[i] - 'a' ]++; o.insert (mo[s[i] - 'a' ]); } if (n % 2 ) { int ans = 0x3f3f3f3f ; for (int i = n - 1 ; i >= 0 ; i--) { if (i % 2 ) { o.erase (o.find (mo[s[i] - 'a' ])); mo[s[i] - 'a' ]--; if (mo[s[i] - 'a' ] == 0 ) mo.erase (s[i] - 'a' ); else o.insert (mo[s[i] - 'a' ]); ans = min (ans, n - *o.rbegin () - *e.rbegin ()); if (me.count (s[i] - 'a' )) e.erase (e.find (me[s[i] - 'a' ])); me[s[i] - 'a' ]++; e.insert (me[s[i] - 'a' ]); } else { e.erase (e.find (me[s[i] - 'a' ])); me[s[i] - 'a' ]--; if (me[s[i] - 'a' ] == 0 ) me.erase (s[i] - 'a' ); else e.insert (me[s[i] - 'a' ]); ans = min (ans, n - *o.rbegin () - *e.rbegin ()); if (mo.count (s[i] - 'a' )) o.erase (o.find (mo[s[i] - 'a' ])); mo[s[i] - 'a' ]++; o.insert (mo[s[i] - 'a' ]); } } cout << ans << '\n' ; } else { cout << n - *e.rbegin () - *o.rbegin () << '\n' ; } } signed main () { int t; cin >> t; while (t--) { solve (); } return 0 ; }