1. 程式人生 > 其它 >Codeforces Round #770(Div.2) [A~D]

Codeforces Round #770(Div.2) [A~D]

連結:contest link

A.Reverse and Concatenate

題目

給定一個長度為 \(n\) 的字串 \(s\) 和一個整數 \(n\) ,用 \(rev(s)\) 表示將字串 \(s\) 反轉,你可以對 \(s\) 執行 \(k\) 次如下操作:

  • \(s\) 變為 \(s+rev(s)\)
  • \(s\) 變為 \(rev(s)+s\)

求可以得到多少個不同的字串

分析

如果 \(s\) 是迴文串,那麼無論執行哪種操作得到的結果都是一樣的,所以執行 \(k\) 次操作後得到的不同字串數為 \(1\)

如果 \(s\) 不是迴文串,那麼 \(k=0\) 時顯然答案為 \(1\)

\(k\geq1\) 時,第一次操作可以將產生兩個不同的迴文串,根據上面對於迴文串的討論,答案為 \(2\)

程式碼

#include<bits/stdc++.h>
using namespace std;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--) {
        int n, k;
        cin >> n >> k;
        string s;
        cin >> s;
        if(k == 0) {
            cout << 1 << endl;
            continue;
        }
        s = ' ' + s;
        bool flag = true;
        for(int i = 1; i <= n / 2; i++) {
            if(s[i] != s[n + 1 - i]) {
                flag = false;
                break;
            }
        }
        cout << (flag ? 1 : 2) << endl;
    }
    return 0;
}

B.Fortune Telling

題目

給定一個長度為 \(n\) 的陣列 \(a\) 和整數 \(x,y\) ,判斷 \(x\)\(x+3\) 進行 \(n\) 次如下操作後能否變為 \(y\) ,第 \(i\) 次操作可以在下面兩條中任選一條執行:

  • 將當前數字 \(d\) 替換為 \(d+a_i\)
  • 將當前數字 \(d\) 替換為 \(d\oplus a_i\)

保證 \(x\)\(x+3\) 中一定有一個能用適當操作變為 \(y\)

分析

  • \(d\) 為偶數
    • \(a_i\) 為偶數,無論執行哪種操作 \(d\) 奇偶性都不變
    • \(a_i\) 為奇數,無論執行哪種操作 \(d\)
      都會變為奇數
  • \(d\) 為奇數
    • \(a_i\) 為偶數,無論執行哪種操作 \(d\) 奇偶性都不變
    • \(a_i\) 為奇數,無論執行哪種操作 \(d\) 都會變為偶數

所以每一種操作對於奇偶性的改變是相同的,那麼判斷遍歷陣列執行操作後 \(x,y\) 奇偶性是否相同即可,若不相同則 \(x\) 無論如何都不能變為 \(y\) ,那 \(x+3\) 一定可以

程式碼

#include<bits/stdc++.h>
using namespace std;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--) {
        long long n, x, y, a;
        cin >> n >> x >> y;
        for(int i = 1; i <= n; i++) {
            cin >> a;
            if(x % 2 && a % 2) {
                x++;
            } else if(x % 2 == 0 && a % 2) {
                x++;
            }
        }
        cout << (x % 2 == y % 2 ? "Alice" : "Bob") << endl;
    }
    return 0;
}

C.OKEA

題目

給定 \(n,k\) 構造一個 \(n\times k\) 的矩陣 \(a\) ,滿足:

  • \(1\)\(n\cdot k\) 的每個整數都出現在矩陣上且僅出現一次
  • 對於任意 \(i,l,r\) 滿足 \(a_{i,l},a_{i,l+1},\cdots,a_{i,r}\) 的算術平均值是整數

分析

可以發現任意一行內的奇偶性是相同的,如果一行內既存在奇數又存在偶數,那麼一定存在一個奇偶相鄰的情況,它們的算術平均值不是整數

若每行的奇偶性都相同,那麼可以構造:

\[\left[\begin{array}{ccc} 1 & 3 & \cdots &2k-1\\ 2 & 4 & \cdots & 2k\\2k+1 & 2k+3 & \cdots & 4k-1\\ \vdots & \vdots & \vdots &\vdots\end{array}\right] \]

對任意一段 \(i,l,r\) 進行求和,可以用等差數列求和公式,可以發現和一定是 \(l+r-1\) 的倍數,那麼算術平均值也一定是整數。進一步,可以求出通項公式 \(a_{i,j}=2(j+k\lfloor\frac{i-1}{2}\rfloor)-i\bmod 2\)

程式碼

#include<bits/stdc++.h>
using namespace std;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--) {
        int n, k;
        cin >> n >> k;
        if((n % 2 && k == 1) || n % 2 == 0) {
            cout << "YES" << endl;
            for(int i = 1; i <= n; i++) {
                for(int j = 1; j <= k; j++)
                    cout << 2 * ((i - 1) / 2 * k + j) - i % 2 << ' ';
                cout << endl;
            }
        } else {
            cout << "NO" << endl;
        }
    }
    return 0;
}

D.Finding Zero

題目

題意較複雜,參考原文 Problem D

分析

考慮一個長度為 \(4\) 的序列 \(a,b,c,d\) ,不妨設 \(a\leq b\leq c\leq d\) ,設 \(\overline{a}=\max(b,c,d)-\min(b,c,d)\) ,進行四次詢問可得:

\[\overline{a}=d-b\\ \overline{b}=d-a\\ \overline{c}=d-a\\ \overline{d}=c-a \]

易知 \(\overline{b},\overline{c}\) 是四次詢問中結果最大的且 \(c\geq b\geq a\) ,序列中的所有數中只有一個 \(0\) 且其他數都大於 \(0\) ,所以對於任意一個長度為 \(4\) 的序列,詢問結果最大的兩個數一定不是 \(0\) ,那麼我們每次處理長度為 \(4\) 的序列,排除掉不可能為 \(0\) 的兩個不可能為 \(0\) 的選項,再繼續加入兩個數,以此類推

這樣當給定長度 \(n\) 為偶數時,要執行 \(\frac{(n-4)}{2}\times 4+4=2n-4\) 次詢問,\(n\) 為奇數時最後會剩下一個長度為 \(3\) 的序列,我們把之前已經排除的某個選項再次加入,使序列長度變為 \(4\) ,要執行 \(\frac{n-1-4}{2}\times4+2\times 4=2n-2\) 次詢問,滿足要求

程式碼

#include<bits/stdc++.h>
using namespace std;

int n;
int del;

int query(int a, int b, int c)
{
    cout << "? " << a << ' ' << b << ' ' << c << endl;
    int res;
    cin >> res;
    return res;
}

vector<int> cal(vector<int> v) 
{
    vector<pair<int, int> > t;
    t.push_back({query(v[1], v[2], v[3]), v[0]});
    t.push_back({query(v[0], v[2], v[3]), v[1]});
    t.push_back({query(v[0], v[1], v[3]), v[2]});
    t.push_back({query(v[0], v[1], v[2]), v[3]});
    sort(t.begin(), t.end());
    del = t.back().second;
    return {t[0].second, t[1].second};
}

void solve() 
{
    cin >> n;
    vector<int>v;
    for(int i = 1; i <= n; i++) {
	 v.push_back(i);
	 if(v.size() == 4)
            v = cal(v);
    }
    if(v.size() == 2) { 
        cout <<"! "<< v[0] << ' ' << v[1] << endl; 
    } else {
	v.push_back(del);
	v = cal(v);
	cout<<"! " << v[0] << ' ' << v[1] << endl;
    }
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--) {
        solve();
    }
    return 0;
}