1. 程式人生 > 其它 >Codeforces Round #732 (Div. 2) A~D題解

Codeforces Round #732 (Div. 2) A~D題解

本場連結:Codeforces Round #732 (Div. 2)

閒話

感覺C/D也沒很簡單,需要一些觀察.由於E/F難度嚴重超出d2就沒做了(也許某天會補進來

A. AquaMoon and Two Arrays

資料範圍不大,考慮直接做:

首先不難觀察到操作並不會改變整個陣列的值,所以兩個陣列之和如果不相同則一定無解.

其次可以如此模擬整個過程:記錄當前需要的差值,如果\(a[i] > b[i]\)則說明某個數需要被增加\(a[i] - b[i]\)反之類似,記錄一個差值\(val\),在做完整個過程之後如果\(val == 0\)則表明整個陣列的差異是平衡的,即有解.反之無解.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)
#define x first
#define y second

const int N = 105;
int a[N],b[N];

int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int n;scanf("%d",&n);
        forn(i,1,n) scanf("%d",&a[i]);
        forn(i,1,n) scanf("%d",&b[i]);
        
        vector<pii> op;
        bool ok = 1;
        forn(i,1,n)
        {
            while(a[i] > b[i])
            {
                int j = 1;
                while(j <= n && a[j] >= b[j])   ++j;
                if(a[j] >= b[j])
                {
                    ok = 0;
                    break;
                }
                op.push_back({i,j});
                --a[i];++a[j];
            }
            if(!ok) break;
        }

        forn(i,1,n) if(a[i] != b[i])    ok = 0;
        
        if(!ok) puts("-1");
        else
        {
            printf("%d\n",(int)op.size());
            for(auto& _ : op)   printf("%d %d\n",_.x,_.y);
        }
    }
    return 0;
}

B. AquaMoon and Stolen String

在已經做完了的數組裡(長度是\(2*n-1\)的),除了被孤立的串,每個串的每個字元相當於被增加了一個.所以被孤立的那個串的每個元素在他的那一列一定是隻出現了奇數個的.找出這樣的一個串就是答案.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)

const int N = 2e5+7;
string s[N];
bool ans[N];

int main()
{
    Angel_Dust;
    int T;cin >> T;
    while(T--)
    {
        int n,m;cin >> n >> m;
        n = 2 * n - 1;
        forn(i,1,n / 2 + 1) ans[i] = 1;
        forn(i,1,n) cin >> s[i];
        forn(i,0,m - 1)
        {
            map<char,int> st;
            forn(j,1,n) ++st[s[j][i]];
            forn(j,1,n / 2 + 1) if(st[s[j][i]] % 2 == 0)    ans[j] = 0;
        }
        string res;
        forn(i,1,n / 2 + 1) if(ans[i])  res = s[i];
        cout << res << endl;
    }
    return 0;
}

C. AquaMoon and Strange Sort

由於要保證操作次數都是偶數,所以對兩個元素進行操作,相當於沒動,最少需要操作三個元素,可以發現對於三個元素進行操作之後,相當於是把三個元素翻轉了,於是可以想到:對於任何兩個位置是奇數/偶數的元素,交換他們兩個是可以保證操作是正確的.即:對任何位置奇偶性相同的元素是可以任意交換的:將所有元素按奇偶位置摳出來,再把兩個數組合並,如果最後得到的陣列是不降的,則說明有解.反之無解.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)

const int N = 1e5+7;
int a[N];

int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        int n;scanf("%d",&n);
        forn(i,1,n) scanf("%d",&a[i]);
        vector<int> odd,even;
        forn(i,1,n) if(i % 2)    odd.push_back(a[i]);else even.push_back(a[i]);
        sort(odd.begin(),odd.end());sort(even.begin(),even.end());
        reverse(odd.begin(),odd.end());reverse(even.begin(),even.end());
        vector<int> res;
        while(!odd.empty() || !even.empty())
        {
            if(!odd.empty())
            {
                res.push_back(odd.back());
                odd.pop_back();
            }
            if(!even.empty())
            {
                res.push_back(even.back());
                even.pop_back();
            }
        }
        bool ok = 1;
        forn(i,0,(int)res.size() - 2)   if(res[i] > res[i + 1]) ok = 0;
        if(!ok) puts("NO");
        else puts("YES");
    }
    return 0;
}

D. AquaMoon and Chess

不難想到應該把:11看做是一個整體進行操作.具體來說,從左到右依次把每個11合併到一個組裡(若前者是個1且自己也是,同時前者不在某個組裡,則合併為一個組),現在整個序列裡只有11;1;0.

我們不妨把1也看做是可以進行移動的,因為在移動了之後,1的形態也不會發生變化,如此可以看做是把序列裡所有的1都刪去(同時不影響方案數的計算).進一步的,因為現在在求每個11相對於\(0\)的位置,所以也相當於求把每個11插入相對於每個\(0\)的位置裡,設有\(m\)個組和\(z\)\(0\),那麼原問題的方案數等價於把\(m\)個球分成\(n+1\)組的方案數,根據隔板法\(ans = \begin{pmatrix}m + z\\m\end{pmatrix}\).故預處理逆元即可計算.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define forn(i,x,n) for(int i = x;i <= n;++i)
#define forr(i,x,n) for(int i = n;i >= x;--i)
#define Angel_Dust ios::sync_with_stdio(0);cin.tie(0)

const int N = 2e5+7,MOD = 998244353;
bool st[N];
char s[N];
int fact[N],infact[N];

int qpow(int a,int b,int MOD)
{
    int res = 1;
    while(b)
    {
        if(b & 1)   res = 1ll * res * a % MOD;
        a = 1ll * a * a % MOD;
        b >>= 1;
    }
    return res;
}

int C(int n,int m)
{
    if(n < m)   return 0;
    int res = fact[n];
    res = 1ll * res * infact[m] % MOD;
    res = 1ll * res * infact[n - m] % MOD;
    return res;
}
int main()
{
    fact[0] = infact[0] = 1;
    forn(i,1,N - 1) fact[i] = 1ll * i * fact[i - 1] % MOD,infact[i] = 1ll * infact[i - 1] * qpow(i,MOD - 2,MOD) % MOD;

    int T;scanf("%d",&T);
    while(T--)
    {
        int n;scanf("%d",&n);
        forn(i,1,n) st[i] = 0;
        scanf("%s",s + 1);

        int m = 0,z = 0;
        forn(i,1,n) if(s[i] == '0') ++z;
        forn(i,1,n - 1)
        {
            if(s[i] == '1' && s[i + 1] == '1' && !st[i])
            {
                st[i] = 1;
                st[i + 1] = 1;
                ++m;
            }
        }
        printf("%d\n",C(m + z,z));
    }
    return 0;
}