1. 程式人生 > 實用技巧 >Codeforces Round #685 (Div. 2) A-F

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