Codeforces Round #685 (Div. 2) A-F
Codeforces Round #685 (Div. 2)
A. Subtract or Divide
題意
給你一個正整數 \(n\), 每次可以執行兩種操作:
- \(n = n-1\)
- \(n = n/x \ (n \% x == 0)\)
問 \(n\) 變成 \(1\), 最小要執行幾次?
思路
- 偶數:直接變成 \(2\), 然後變成 \(1\),
- 奇數:先減 \(1\), 變成 \(2\), 然後變成 \(1\)
程式碼
#include <bits/stdc++.h> #define lowbit(x) x & (-x) #define mes(a, b) memset(a, b, sizeof a) #define fi first #define se second #define pb push_back #define pii pair<int, int> typedef unsigned long long int ull; typedef long long int ll; const int maxn = 1e6 + 10; const int maxm = 1e5 + 10; const ll mod = 1e9 + 7; const ll INF = 1e18 + 100; const int inf = 0x3f3f3f3f; const double pi = acos(-1.0); const double eps = 1e-8; using namespace std; int main() { int T, n; scanf("%d", &T); while(T--) { scanf("%d", &n); if(n <= 3) printf("%d\n", n-1); else if (n % 2) printf("%d\n", 3); else printf("2\n"); } return 0; }
B. Non-Substring Subsequence
題意
給你一個長度為 \(n\) 的 \(01\) 字串 \(a\), \(q\) 個詢問,每次詢問能否在字串 \(a\) 中找到不連續的子序列 \(b\) 等於 \(a[l_i...r_i]\)。
思路
列舉 \(l, r\) 被斷開的位置,其他位置暴力查詢即可。
程式碼
#include <bits/stdc++.h> #define pb push_back #define fi first #define se second #define mes(a, b) memset(a, b, sizeof a) using namespace std; typedef unsigned long long ull; typedef long long ll; const int maxn = 1e3 + 100; const int mx = 1e5; const ull seed = 133331; const ll inf = 1e15; int T, n, m; char a[maxn]; int main() { scanf("%d", &T); while(T--) { scanf("%d%d%s", &n, &m, a+1); int l, r; while(m--) { scanf("%d%d", &l, &r); int flag = 0, w; for(int i = l; i < r && !flag; i++) { w = 1; for(int j = l; j <= i; j++) { while(w <= n && a[w] != a[j]) w++; w++; } w++; //因為斷開,所以這邊要++ for(int j = i+1; j <= r; j++) { while(w <= n && a[w] != a[j]) w++; w++; } if(w <= n+1) flag = 1; } puts(flag ? "YES" :"NO"); } } return 0; }
C. String Equality
題意
給你兩個字串 \(a, b\) ,可以對字串 \(a\) 進行兩種操作:
- 交換任意兩個字元
- 把連續相同的 \(k\) 個字元 \(c\) 轉變為 \(c+1\) (’\(z\)‘ 字元無法轉變 )
問字串 \(a\), 是否能在有限制操作內轉變為字串 \(b\)。
思路
因為可以任意交換位置,所以把字串 \(a\), \(b\) ,進行排序,每次暴力轉變即可。
程式碼
#include <bits/stdc++.h> #define lowbit(x) x & (-x) #define mes(a, b) memset(a, b, sizeof a) #define fi first #define se second #define pb push_back #define pii pair<int, int> typedef unsigned long long int ull; typedef long long int ll; const int maxn = 1e6 + 10; const int maxm = 1e5 + 10; const ll mod = 1e9 + 7; const ll INF = 1e18 + 100; const int inf = 0x3f3f3f3f; const double pi = acos(-1.0); const double eps = 1e-8; using namespace std; int T, n, m; char ch[maxn]; int a[30], b[30]; int main() { scanf("%d", &T); while(T--) { mes(a, 0); mes(b, 0); scanf("%d%d", &n, &m); scanf("%s", ch+1); for(int i = 1; i<= n; i++) a[ch[i]-'a']++; scanf("%s", ch+1); for(int i = 1; i <= n; i++) b[ch[i]-'a']++; int flag = 1; for(int i = 0; i < 26 && flag; i++) { if(a[i] < b[i]) flag = 0; if((a[i] - b[i]) % m) flag = 0; a[i+1] += a[i] - b[i]; } puts(flag?"Yes":"No"); } return 0; }
D. Circle Game
題意
起始點在 \((0, 0)\) , 每次可以讓 \(x+k\), 或者 \(y + k\) , 並且使得走之後位置 \((x_1, y_1)\),滿足 \(x_1^2 + y_1^2 \le d^2\)。\(Ashish\) 為先手,誰不能走則輸了,問誰能贏得這次遊戲?
思路
找最大的\(x\), 滿足 \(x^2 + x^2 \le d^2\)
- \((x+k)^2 + x^2 \le d\), 則先手勝
- \((x+k)^2 + x^2 > d\), 則先手敗
\((x+k)^2 + x^2 > d\) 時,先手走 \(x+k\), 那麼後手走 \(y+k\), 控制 \(x = y\) 即可。如果\((x+k)^2 + x^2 \le d\),則先手走一步之後可以把狀態轉變為 \((x+k)^2 + x^2 > d\) , 就必勝了。
程式碼
#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxn = 1e6 + 100;
const int mx = 1e5;
const ull seed = 133331;
const ll inf = 1e15;
ll T, n, m;
int main() {
scanf("%lld", &T);
while(T--) {
scanf("%lld%lld", &n, &m);
ll x = max(int(sqrt(n * n) / 2/ m)-2, 0);
x *= m;
while(x * x * 2 <= n * n) x += m;
x -= m;
if(x * x + (x+m) * (x+m) <= n*n || x*x*2 > n*n)
puts("Ashish");
else puts("Utkarsh");
}
return 0;
}
E1、E2. Bitwise Queries
題意
給你一個長度為 \(n\) \((4 \le n \le 2^{16}, n = 2^k)\) 的陣列 \(a \ (a_i \in [0, n-1])\), 可以執行以下三種詢問。
-
\(AND\ i\ j\) , 詢問 \(a_i \ \& \ a_j\)
-
\(XOR\ i\ j\) , 詢問 \(a_i \oplus a_j\)
-
\(OR\ i\ j\), 詢問 \(a_i\ | \ a_j\)
在最多執行 \(n+1\) 次詢問中,猜出原陣列 \(a\) 的值。
思路
-
根據題目給的限制可以知道,要麼陣列存在兩個相同的值,要麼陣列是一個 \(0\) ~ \(n-1\) 的排列。
-
首先執行 \(XOR\ 1\ i\), \(2 \le i \le n\)。
-
判斷是否出現 \(a_1 \oplus a_i = 0\), 那麼執行 \(AND\ 1\ i\),因為 \(a_1 = a_i\), 就可以知道 \(a_1\) 的值
-
判斷是否出現 \(a_1 \oplus a_i = 0, a_1 \oplus a_j = 0\) ,那麼執行 \(AND\ i\ j\),因為 \(a_i = a_j\), 就可以知道 \(a_i\) 的值
-
否則找出 \(a_1 \oplus a_i = 1, a_1 \oplus a_j = 2\), 那麼執行 \(AND \ 1\ i\)、 \(AND \ 1\ j\),所以 \(a_1 = (a_1 \&a_i) | (a_1\&a_j)\)
程式碼
#include <bits/stdc++.h>
#define lowbit(x) x & (-x)
#define mes(a, b) memset(a, b, sizeof a)
#define fi first
#define se second
#define pb push_back
#define pii pair<int, int>
typedef unsigned long long int ull;
typedef long long int ll;
const int maxn = 1e6 + 10;
const int maxm = 1e5 + 10;
const ll mod = 1e9 + 7;
const ll INF = 1e18 + 100;
const int inf = 0x3f3f3f3f;
const double pi = acos(-1.0);
const double eps = 1e-8;
using namespace std;
int T, n, m;
int a[maxn], b[maxn], c[maxn];
int main() {
scanf("%d", &n);
for(int i = 2; i<= n; i++) {
printf("XOR %d %d\n", 1, i);
fflush(stdout);
scanf("%d", &b[i]);
}
int flag = 0, x, y;
for(int i = 2; i <= n; i++) {
if(!b[i]) {
printf("AND 1 %d\n", i);
fflush(stdout);
scanf("%d", &a[1]);
flag = 1;
break;
}
if(c[b[i]]) {
printf("AND %d %d\n", c[b[i]], i);
fflush(stdout);
scanf("%d", &a[i]);
a[1] = a[i] ^ b[i];
flag = 1;
break;
}
c[b[i]] = i;
}
if(!flag) {
for(int i = 2; i <= n; i++) {
if(b[i] == 1) {
printf("AND 1 %d\n", i);
fflush(stdout);
scanf("%d", &x);
}
if(b[i] == 2) {
printf("AND 1 %d\n", i);
fflush(stdout);
scanf("%d", &y);
}
}
a[1] = x|y;
}
printf("! %d ", a[1]);
for(int i = 2; i<= n; i++) {
printf("%d ", a[1] ^ b[i]);
}
printf("\n");
return 0;
}
F. Nullify The Matrix
題意
你有一個 \(n*m\) 的矩陣,\(Ashish\) 為先手,每輪可以執行以下操作,直到當前不能操作為止(既全0矩陣)
- 你可以選擇一個起點 \((r_1, c_1)\) , 選擇一個終點 \((r_2, c_2)\) ,滿足 \(r_1 \le r_2, c_1 \le c_2\)
- 把 \(a[r1][c1]\) 減小至 \([0, a[r1][c1]-1]\)
- 選擇任意一條起點到終點的最短路徑,可以把除起點外的任意一點修改成任一非負數(每個單元格修改獨立)
思路
-
可以把矩陣中 \(r_x+c_x\) 相同的為一組,當執行一次操作的時候,是對從 \([c_1+r_1,\ c_1+r_1+1,\ c_1+r_1+2,\ ...,\ c_2+r_2]\) 中的每一組中選擇一個元素進行修改,
-
\(ord(d) = a[r_1][c_1]\oplus a[r_2][c_2] \oplus ... a[r_x][c_x]\ \ \forall_{i=1}^x r_i +c_i = d\) 。 那麼存在兩種狀態
- \(S_0 : \forall ord(d) = 0\)
- \(S_1:\in ord(d) \neq 0\)
-
最終態為 \(S_0\) 。
- 當在 \(S_0\) 狀態上執行一步,一定會轉變為 $ S_1$
- 當在 \(S_1\) 狀態上執行一步,可以轉變為 \(S_0\) , 只要把每組 \(ord(d) \neq 0\) 中取出一個變為組內其他值的異或和既可。
-
當初始狀態為 \(S_0\) 時,後手必贏。反之,後手必敗。
程式碼
#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define mes(a, b) memset(a, b, sizeof a)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxn = 1e3 + 100;
const int mx = 1e5;
const ull seed = 133331;
const ll inf = 1e15;
int n, m, T;
int a[maxn];
int main() {
scanf("%d", &T);
while(T--) {
mes(a, 0);
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++) {
for(int j = 1, x; j <= m; j++) {
scanf("%d", &x);
a[i+j] ^= x;
}
}
int flag = 0;
for(int i = 2; i <= m+n; i++) {
if(a[i]) flag = 1;
}
puts(flag ? "Ashish" : "Jeel");
}
return 0;
}