1. 程式人生 > 其它 >Codeforces Round #696 (Div. 2) 部分簡要題解

Codeforces Round #696 (Div. 2) 部分簡要題解

技術標籤:# Codeforces

A. Puzzle From the Future

貪心,每位儘可能取1,如果不能取1,就取0。

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 

int main()
{
    ios ;
    int T ;
    cin >> T ;
    while(T --)
    {
        int n ;
        cin >> n ;
        string s ;
        cin >> s ;
        vector<int> a(n + 1) , b(n + 1) ;
        for(int i = 1 ; i <= n ; i ++)  a[i] = (s[i - 1] - '0') ;
        b[1] = 1 ;
        for(int i = 2 ; i <= n ; i ++)
        {
            int lst = a[i - 1] + b[i - 1] ;
            for(int j = 1 ; j >= 0 ; j --)
            {
                if(a[i] + j != lst)
                {
                    b[i] = j ;
                    break ;
                }
            }
        }
        for(int i = 1 ; i <= n ; i ++)  cout << b[i] ;
        cout << '\n' ;
    }
    return 0 ;
}

B. Different Divisors

a=p_1*p_2,其中p_1,p_2是質數。列舉p_1,p_2即可。注意素數篩的範圍略大一些,40000就夠用了。

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
int ans[maxn] ;
struct Easymath
{
    ll qpow(ll a , ll b) //快速冪
    {
        if(b < 0)  return 0 ;
        ll ans = 1 ; 
        a %= mod ;
        while(b)
        {
            if(b & 1)  ans = (ans * a) % mod ;
            b >>= 1 , a = (a * a) % mod ;
        }
        return ans % mod ;
    }
    ll ksc_log(ll x , ll y , ll mod) //快速乘
    {
        x %= mod , y %= mod ;
        ll ans = 0;
        while(y)
        {
            if(y & 1) ans = (ans + x) % mod ; 
            y >>= 1 ;
            x = (x + x) % mod ;
        }
        return ans;
    }
    ll ksc_O1(ll x , ll y , ll mod) //快速乘
    {
        x %= mod , y %= mod ;
        ll z = (ld)x * y / mod ;
        ll ans = x * y - z * mod ;
        if(ans < 0)  ans += mod ;
        else if(ans >= mod)  ans -= mod ;
        return ans ;
    }
    int cnt = 0 ;
    bool vis[maxn] ;
    int prime[maxn] ;
    void get_prime(int up) //素數篩
    {
        memset(vis , 0 , sizeof(vis)) ;
        vis[1] = 1 ;
        for(int i = 2 ; i <= up ; i ++)
        {
            if(!vis[i]) 
            prime[++ cnt] = i ;
            for(int j = 1 ; j <= cnt && i * prime[j] <= up ; j ++)
            {
                vis[i * prime[j]] = 1 ;
                if(i % prime[j] == 0) break ;
            }
        }
        mem_inf(ans) ;
        for(int i = 1 ; i <= cnt ; i ++)  for(int j = i + 1 ; j <= cnt ; j ++)
        {
            int mn = min(prime[i] - 1 , prime[j] - prime[i]) ;
            ans[mn] = min(ans[mn] , prime[i] * prime[j]) ;
        }
        for(int i = 20000 ; i >= 1 ; i --)  ans[i] = min(ans[i + 1] , ans[i]) ;
    }
    //begin 判定大素數
    ll mul(ll a , ll b , ll mod)
    {
        ll ret = 0 ;
        while(b) 
        {
            if(b & 1)  ret = (ret + a) % mod ;
            a = (a + a) % mod ;
            b >>= 1 ;
        }
        return ret ;
    }
    ll pow(ll a , ll b , ll mod)
    {
        ll ret = 1 ;
        while(b) 
        {
            if(b & 1)  ret = mul(ret , a , mod) ;
            a = mul(a , a , mod) ;
            b >>= 1 ;
        }
        return ret ;
    }
    bool check(ll a , ll n)
    {
        ll x = n - 1 ;
        int t = 0 ;
        while((x & 1) == 0) 
        {
            x >>= 1 ;
            t ++ ;
        }
        x = pow(a , x , n) ;
        ll y ;
        rep(i , 1 , t)
        {
            y = mul(x , x , n) ;
            if(y == 1 && x != 1 && x != n - 1)  return 1 ;
            x = y ;
        }
        if(y != 1) return 1 ;
        return 0 ;
    }
    bool Miller_Rabin(ll n) 
    {
        if(n == 2)  return 1 ;
        if(n == 1 || !(n & 1))  return 0 ;
        const int arr[12] = {2,3,5,7,11,13,17,19,23,29,31,37} ;
        rep(i , 0 , 11) 
        {
            if(arr[i] >= n) break ;
            if(check(arr[i] , n)) return 0 ;
        }
        return 1 ;
    }
    //end 判定大素數
    ll get_inv(ll x) //逆元
    {
       return qpow(x , mod - 2) % mod ;
    }
    ll inv1[maxn] ;  //乘法逆元
    void init1(int up)
    {
       inv1[1] = 1 ;
       for(int i = 2 ; i <= up ; i ++)
         inv1[i] = (ll)(mod - mod / i) * inv1[int(mod % (ll)i)] % mod ;
    }
    ll fac[maxn] ;
    ll inv[maxn] ; //階乘逆元
    void init(int up) 
    {
       fac[0] = fac[1] = inv[0] = inv[1] = 1 ;
       for(int i = 2 ; i <= up ; i ++)
       {
         fac[i] = fac[i - 1] * i % mod ;
         inv[i] = -inv[mod % i] * (mod / i) % mod ;
         while(inv[i] < 0) inv[i] += mod ;
       }
       for(int i = 2 ; i <= up ; i ++)  
         inv[i] = inv[i] * inv[i - 1] % mod ;
    }
    ll C(int n , int m)
    {
        return fac[n] * inv[m] % mod * inv[n - m] % mod ;
    }
} em ;
int main()
{
    ios ;
    int T ;
    em.get_prime(40005) ;
    cin >> T ;
    while(T --)
    {
        int d ;
        cin >> d ;
        cout << ans[d] << '\n' ;
    }
    return 0 ;
}

C. Array Destruction

在第一次操作時,序列的最大數一定是其中一個運算元,列舉另一個運算元即可。在後續操作中,每次操作的兩個運算元都是固定的。複雜度O(n^2)

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 1e6 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ; 
int cnt[maxn] ;
int main()
{
    ios ;
    int T ;
    cin >> T ;
    while(T --)
    {
        int n ;
        cin >> n ;
        n *= 2 ;
        vector<int> a(n) ;
        for(int i = 0 ; i < n ; i ++)  cin >> a[i] ;
        sort(all(a)) ;
        for(int i = 0 ; i < n - 1 ; i ++)
        {
            bool flag = true ;
            int now = a[i] + a[n - 1] ;
            for(int j = 0 ; j < n ; j ++)  cnt[a[j]] ++ ;
            if(cnt[a[i]] > 0)  cnt[a[i]] -- ;
            if(cnt[a[n - 1]] > 0)  cnt[a[n - 1]] -- ;
            now = a[n - 1] ;
            for(int j = n - 2 ; j >= 0 ; j --)
            {
                if(cnt[a[j]] == 0)  continue ;
                cnt[a[j]] -- ;
                if(cnt[now - a[j]] == 0)  flag = false ;
                if(cnt[now - a[j]] > 0)  cnt[now - a[j]] -- ;
                now = a[j] ;
            }
            if(flag)
            {
                cout << "YES\n" ;
                for(int j = 0 ; j < n ; j ++)  cnt[a[j]] = 0 ;
                int now = a[i] + a[n - 1] ;
                cout << now << '\n' ;
                for(int j = 0 ; j < n ; j ++)  cnt[a[j]] ++ ;
                if(cnt[a[i]] > 0)  cnt[a[i]] -- ;
                if(cnt[a[n - 1]])  cnt[a[n - 1]] -- ;
                cout << a[i] << ' ' << a[n - 1] << '\n' ;
                now = a[n - 1] ;
                for(int j = n - 2 ; j >= 0 ; j --)
                {
                    if(cnt[a[j]] == 0)  continue ;
                    cnt[a[j]] -- ;
                    if(cnt[now - a[j]] == 0)  flag = false ;
                    if(cnt[now - a[j]] > 0)  cnt[now - a[j]] -- ;
                    cout << a[j] << ' ' << now - a[j] << '\n' ;
                    now = a[j] ;
                }
                goto ff ;
            }
            for(int j = 0 ; j < n ; j ++)  cnt[a[j]] = 0 ;
        }
        cout << "NO\n" ;
        ff : ;
        for(int i = 0 ; i < n ; i ++)  cnt[a[i]] = 0 ;
    }
    return 0 ;
}

D. Cleaning

套路題。

首先容易發現a[1],a[2],a[3],...,a[n]在對a[1]操作後會變成a[2]-a[1],a[3],...a[n]

a[1],a[2],a[3],...,a[n]在對a[n]操作後會變成a[1],a[2],a[3],...,a[n-1]-a[n]

然後發現如果swap(a[i],a[i+1]),最多會影響a[i-1],a[i+2]

所以預處理字首和字尾,列舉swap(a[i],a[i+1])即可。

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 1e6 + 10 ;
int main()
{
    ios ;
    int T ;
    cin >> T ;
    while(T --)
    {
        int n ;
        cin >> n ;
        vector<int> a(n) ;
        vector<int> pre(n) ;
        vector<int> suf(n) ;
        vector<int> pre_cnt(n , 0) ;
        vector<int> suf_cnt(n , 0) ;
        for(int i = 0 ; i < n ; i ++)  cin >> a[i] ;
        function<void()> init = [&]()
        {
            pre[0] = a[0] ;
            pre_cnt[0] = 0 ;
            for(int i = 1 ; i < n ; i ++)
            {
                int mn1 = pre[i - 1] ;
                int mn2 = a[i] ;
                int mn = min(mn1 , mn2) ;
                mn1 -= mn ;
                mn2 -= mn ;
                pre[i] = mn2 ;
                pre_cnt[i] = pre_cnt[i - 1] + (mn1 != 0) ;
            }

            suf[n - 1] = a[n - 1] ;
            suf_cnt[n - 1] = 0 ;
            for(int i = n - 2 ; i >= 0 ; i --)
            {
                int mn1 = suf[i + 1] ;
                int mn2 = a[i] ;
                int mn = min(mn1 , mn2) ;
                mn1 -= mn ;
                mn2 -= mn ;
                suf[i] = mn2 ;
                suf_cnt[i] = suf_cnt[i + 1] + (mn1 != 0) ;
            }
            //for(int i = 0 ; i < n ; i ++)  cout << suf[i] << " \n"[i == n - 1] ;
            //for(int i = 0 ; i < n ; i ++)  cout << suf_cnt[i] << " \n"[i == n - 1] ;
        } ;
        init() ;
        function<bool()> ok = [&]()
        {
            vector<int> b(n) ;
            for(int i = 0 ; i < n ; i ++)  b[i] = a[i] ;
            for(int i = 0 ; i < n - 1 ; i ++)
            {
                int mn = min(b[i] , b[i + 1]) ;
                b[i] -= mn ;
                b[i + 1] -= mn ;
            }
            for(int i = 0 ; i < n ; i ++)  if(b[i] != 0)  return false ;
            return true ;
        } ;
        function<bool(int)> ok2 = [&](int t)
        {
            int lst = 0 ;
            if(t - 1 >= 0)  lst += pre[t - 1] ;
            if(t - 1 >= 0 && pre_cnt[t - 1] >= 1)  return false ;

            int nxt = 0 ;
            if(t + 2 < n)  nxt += suf[t + 2] ;
            if(t + 2 < n && suf_cnt[t + 2] >= 1)  return false ;
            int now1 = a[t] ;
            int now2 = a[t + 1] ;
            swap(now1 , now2) ;
            //cout << lst << ' ' << now1 << ' ' << now2 << ' ' << nxt << '\n' ;
            int mn1 = min(lst , now1) ;
            lst -= mn1 ;
            now1 -= mn1 ;
            int mn3 = min(now1 , now2) ;
            now1 -= mn3 ;
            now2 -= mn3 ;
            int mn2 = min(nxt , now2) ;
            nxt -= mn2 ;
            now2 -= mn2 ;
            //cout << lst << ' ' << now1 << ' ' << now2 << ' ' << nxt << '\n' ;
            return lst == 0 && now1 == 0 && nxt == 0 && now2 == 0 ;
        } ;
        //cout << ok2(0) << '\n' ;
        bool flag = ok() ;
        for(int i = 0 ; i < n - 1 ; i ++)  flag |= ok2(i) ;
        if(flag)  cout << "YES\n" ;
        else  cout << "NO\n" ;
    }
    return 0 ;
}

E. What Is It?

逆向思考,把恆等排列變成某個排列,需要花費最大代價是多少。操作次數是n-1,每次選擇一個p[i]=i,然後和p[1]p[n]交換,選擇較遠的那個交換。

寫程式碼時要對n的奇偶性分類討論。

#include<bits/stdc++.h>
using namespace std ;
int main()
{
    std::ios::sync_with_stdio(false) , cin.tie(0) ;
    int T ;
    cin >> T ;
    while(T --)
    {
        int n ;
        cin >> n ;
        vector<int> p(n + 1) ;
        for(int i = 1 ; i <= n ; i ++)  p[i] = i ;
        vector<pair<int , int>> t ;
        long long ans = 0 ;
        if(n % 2 == 1)
        {
            swap(p[1] , p[n]) ;
            t.push_back({1 , n}) , ans += 1ll * (n - 1) * (n - 1) ;
            for(int i = 2 ; i <= n / 2 ; i ++)
            {
                swap(p[i] , p[n]) ;
                t.push_back({i , n}) , ans += 1ll * (n - i) * (n - i) ;
                swap(p[n + 1 - i] , p[1]) ;
                t.push_back({n + 1 - i , 1}) , ans += 1ll * (n - i) * (n - i) ;
            }
            swap(p[(n + 1) / 2] , p[1]) ;
            t.push_back({(n + 1) / 2 , 1}) , ans += 1ll * ((n + 1) / 2 - 1) * ((n + 1) / 2 - 1) ;
        }
        else
        {
            swap(p[1] , p[n]) ;
            t.push_back({1 , n}) , ans += 1ll * (n - 1) * (n - 1) ;
            for(int i = 2 ; i <= n / 2 ; i ++)
            {
                swap(p[i] , p[n]) ;
                t.push_back({i , n}) , ans += 1ll * (n - i) * (n - i) ;
                swap(p[n + 1 - i] , p[1]) ;
                t.push_back({n + 1 - i , 1}) , ans += 1ll * (n - i) * (n - i) ;
            }
        }
        cout << ans << '\n' ;
        for(int i = 1 ; i <= n ; i ++)  cout << p[i] << " \n"[i == n] ;
        cout << t.size() << '\n' ;
        reverse(t.begin() , t.end()) ;
        for(auto u : t)  cout << u.first << ' ' << u.second << '\n' ;
    }
    return 0 ;
}

F. 1 2 3 4 ...

標程太長,告辭。