Good Bye 2022: 2023 is NEAR

中文题面

中文题解

A. Koxia and Whiteboards

因为必须要对\(a_i\)做替换,那么把\(a_i\)中最小的替换掉是最优的

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

int read(){
    int x = 0 , f = 1 , ch = getchar();
    while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
    if( ch == '-' ) f = -1 , ch = getchar();
    while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
    return x * f;
}

void solve(){
    int n = read() , m = read() , res = 0;
    multiset<int> a;

    for( int i = 1 , x ; i <= n ; i ++ )
        x = read() , a.insert(x);
    for( int i = 1 , x ; i <= m ; i ++ )
       x = read() , a.erase( a.begin() ) , a.insert(x);
    for( auto i : a )
        res += i;
    printf("%lld\n" , res );

}

int32_t main(){
    for( int t = read() ; t ; t -- )
        solve();
}

B. Koxia and Permutation

要构造这样的序列,要知道,全局最大一定是对答案有贡献的,那么除了全局最大之外,还要加一个区间最小值,那么最优的情况就是让包含全局最大的区间最小值都是全局最小。如果要实现这一步必须使得全局最大值在边界上,全局最小最小在距离边界为k的位置上。那么此时两个数之间的值都是不可能产生贡献的,就尽可能填大的值就好了。然后利用这个规则填剩余的位置。

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


int read(){
    int x = 0 , f = 1 , ch = getchar();
    while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
    if( ch == '-' ) f = -1 , ch = getchar();
    while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
    return x * f;
}

void solve(){
    int n = read() , k = read() , val = INT_MAX;
    vector<int> a(n+1);
    if( k == 1 || k == n ){
        for( int i = 1 ; i <= n ; i ++ )
            cout << i << " ";
        cout << "\n";
        return;
    }
    set<int> s;
    for( int i = 1 ; i <= n ; i ++ ) s.insert(i);
    for( int i = 1 ; i <= n ; i += k ){
        if( i+k-1 > n ){
            for( int j = i ; j <= n ; j ++ )
                a[j] = *s.rbegin() , s.erase(*s.rbegin());
            break;
        }
        a[i] = *s.rbegin() , a[i+k-1] = *s.begin();
        s.erase( *s.rbegin() ) , s.erase( s.begin() );
        for( int j = i+1 ; j < i+k-1 ; j ++ )
            a[j] = *s.rbegin() , s.erase(*s.rbegin());

    }
    for( int i = 1 ; i <= n ; i ++ )
        cout << a[i] << " ";
    cout << "\n";
    return;

}

int32_t main(){
    for( int t = read() ; t ; t -- )
        solve();
}

C. Koxia and Number Theory(补题)

首先很容易推出如果存在\(a_i=a_j\)的情况是一定找不到的。

然后我们发现如果有两个以上的奇数和两个以上的偶数一定找不到,让两个偶数互质,\(x\)一定是奇数,而奇数\(x\)又会使两个奇数变成偶数。

在以上的结论中可以进行扩展,对于一个因子\(k\),如果$a_i \mod k \(的集合中,\)[0,k-1]\(中的每个数都出现了至少两次,那么就一定找不到\)x\(,为什么呢?因为则这种情况下,无论\)x\(是何值,都一定会导致至少某两个数满足\)(a_i+x) \mod k = 0\(此时两个数都是\)k$的倍数自然不可能互质。

如果让\(k\)满足上述不可避免的条件至少需要\(2k\)个数,因为\(n\)最大为100,所以当\(k\)大于50后一定不会满足上述条件。所以暴力\(k\in [2,50]\)的所以情况就好。

本题的证明感觉还是很难,可以参考官方题解,不得不说这场有官方的中文体面和题解补题的时候真舒服

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

int read(){
    int x = 0 , f = 1 , ch = getchar();
    while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
    if( ch == '-' ) f = -1 , ch = getchar();
    while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
    return x * f;
}

void solve(){
    int n = read();
    vector<int> a(n);
    set<int> s;
    for( auto & i : a ) i = read() , s.insert(i);
    if( s.size() < n ){
        printf("NO\n");
        return;
    }
    for( int i = 2 ; i <= 50 ; i ++ ){
        vector<int> t(i);
        for( auto j : a ) t[ j%i ] ++;
        bool flag = false;
        for( auto j : t )
            if( j < 2 ) {
                flag = true;
                break;
            }
        if( flag ) continue;
        printf("NO\n");
        return;
    }
    printf("YES\n");
    return;
}

int32_t main(){
    for( int t = read() ; t ; t -- )
        solve();
    return 0;
}

D. Koxia and Game(补题)

其实看题解应该就很好理解了,我来解释一下为什么题解中要给边规定方向吧。现在联通分量中有\(n\)个点\(n\)条边,对于每一条边来说实际上一个二选一,比如我们都选有向边的终点,那么对于一个简单环,只要确定了任意一条边的方向,整个环的方向就确定了。如果环上再跟一些链的话,如果环的方向确定后链的方向也是唯一的,所以对于一个环有两种选择方案。自环的情况类似,当自环确定其他的也就确定了,只是对于自环本身来说\(c_i\)值是无所谓的,所以有\(n\)种方案。

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

int read(){
    int x = 0 , f = 1 , ch = getchar();
    while( (ch < '0' || ch > '9') && ch != '-' ) ch = getchar();
    if( ch == '-' ) f = -1 , ch = getchar();
    while( ch >= '0' && ch <= '9' ) x = ( x << 3 ) + ( x << 1 ) + ch - '0' , ch = getchar();
    return x * f;
}

const int mod = 998244353;

void solve(){
    int n = read();
    vector<int> a(n+1) , cntV( n+1, 1 ) , cntE( n+1 , 0 ) , selfloop( n+1 , 0 ) , vis( n+1 , 0 );
    auto b = a , fa = a;
    for( int i = 1 ; i <= n ; i ++ ) a[i] = read();
    for( int i = 1 ; i <= n ; i ++ ) b[i] = read();
    for( int i = 1 ; i <= n ; i ++ ) fa[i] = i;

    function<int(int)> getfa = [&]( int x ){
        if( fa[x] == x ) return x;
        return fa[x] = getfa( fa[x] );
    };

    auto merge = [&]( int u , int v ) ->void {
        u = getfa(u) , v = getfa(v);
        cntV[u] += cntV[v] , cntE[u] += cntE[v] , selfloop[u] |= selfloop[v];
        fa[v] = u;
    };

    for( int i = 1 ; i <= n ; i ++ ){
        if( getfa(a[i]) != getfa(b[i]) ) merge( a[i] , b[i] );
        cntE[ getfa(a[i]) ] ++;
        if( a[i] == b[i] ) selfloop[ getfa( a[i] ) ] = 1;
    }
    int res = 1;
    for( int i = 1 , t ; i <= n ; i ++ ) if( vis[ getfa(i) ] == 0 ){
        t = getfa(i);
        if( cntE[t] != cntV[t] ) res = 0;
        else res = res * ( selfloop[t] ? n : 2 ) % mod;
        vis[t] = 1;
    }
    printf("%lld\n" , res );
}

int32_t main(){
    for( int t = read() ; t ; t -- )
        solve();
    return 0;
}
posted @ 2023-01-08 15:11  PHarr  阅读(26)  评论(0编辑  收藏  举报