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\) 。 那么存在两种状态

    1. \(S_0 : \forall ord(d) = 0\)
    2. \(S_1:\in ord(d) \neq 0\)
  • 最终态为 \(S_0\)

    1. 当在 \(S_0\) 状态上执行一步,一定会转变为 $ S_1$
    2. 当在 \(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;
}
posted @ 2020-11-24 19:55  竹攸  阅读(135)  评论(0编辑  收藏  举报