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