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;
}