目录
涵盖知识点:思维、构造、树上倍增。
比赛链接:传送门
博客园目录好像不能用toc了???容我研究一下。。。
A - Divisibility Problem
题意: 给两个数\(a,b\),每次操作可以使\(a=a+1\),问最少几次操作后\(a\)是\(b\)的倍数。
题解:
Accept Code:
#include <bits/stdc++.h>
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
int a,b;
cin>>a>>b;
if(a%b==0){cout<<"0\n";continue;}
if(a<=b)cout<<b-a<<"\n";
else cout<<b-(a%b)<<"\n";
}
return 0;
}
B - K-th Beautiful String
题意: 长度为\(n\)的字符串包含\(n-2\)个a和\(2\)个b,求按照字典序排列的第\(k\)个。
题解: 观察样例,左边的b的位置出现次数按照\(1,2,3\ldots\)排列,确定后再确定右边的b的出现位置即可。
Accept Code:
#include <bits/stdc++.h>
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
int n,k;
cin>>n>>k;
int l=1;
while(k>l)k-=l,l++;
l++;
int r=k;
for(int i=n;i>=1;i--){
if(i==l||i==r)cout<<"b";
else cout<<"a";
}
cout<<"\n";
}
return 0;
}
C - Ternary XOR
题意: 规定三进制下的运算\(c = a \odot b\)为\(c_i = (a_i + b_i) \% 3\),现给定\(c\),要求构造\(a,b\),并使得\(max(a,b)\)尽可能小。
题解: 第一个1分配给\(a\),后面的所有数字一律分配给\(b\)。
Accept Code:
#include <bits/stdc++.h>
using namespace std;
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
string s,a,b;
cin>>s;
bool flag=true;
for(char i : s){
if(flag) {
if (i == '0')a += '0', b += '0';
if (i == '1')a += '1', b += '0',flag=false;
if (i == '2')a += '1', b += '1';
}else a+='0',b+=i;
}
cout<<a<<"\n"<<b<<"\n";
}
return 0;
}
D - Carousel
题意: \(n\)个动物围成一个环,现在要给动物上色,要求不能给相邻的不同动物上同一种颜色,问最少几种颜色可以满足条件。
题解:
- 全同色,1种
- 不存在相邻的相同动物且为奇数,3种。(前面1,2间隔最后一个3)
- 其余情况两种。偶数(12121212)奇数(找组相邻相同的把12反向)
画个图脑补一下就好了。
Accept Code:
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int a[maxn];
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
a[0]=a[n];
bool flag=true;
for(int i=1;i<=n;i++){
if(a[i]!=a[i-1]){
flag=false;
break;
}
}
if(flag){
cout<<"1\n";
for(int i=1;i<=n;i++)cout<<1<<" ";
cout<<"\n";
continue;
}
int pos=0;
for(int i=1;i<=n;i++){
if(a[i]==a[i-1])
pos=i;
}
if(!pos&&(n&1)){
cout<<"3\n";
for(int i=1;i<n;i++)cout<<i%2+1<<" ";
cout<<"3\n";
}
else{
cout<<"2\n";
if(!(n&1)){
for(int i=1;i<=n;i++)cout<<i%2+1<<" ";
cout<<"\n";
}else{
for(int i=1;i<pos;i++)cout<<i%2+1<<" ";
for(int i=pos;i<=n;i++)cout<<2-i%2<<" ";
cout<<"\n";
}
}
}
return 0;
}
E - Tree Queries
题意: 给定一颗1为根的\(n\)顶点根树。对于\(m\)个询问,每个询问给\(k\)个点,问是否存在1出发的一条链使得这\(k\)个点距离链的距离小于1。
题解: 在\(k\)个点里找深度最大的点为该链终点。扫描一下其他的点即可。暴力肯定不能过,倍增优化一下跳跃步长就行了。
Accept Code:
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
const int maxd=20;
vector<int> edg[maxn];
int fa[maxn][maxd];
int deg[maxn];
int vi[maxn];
void bfs(int root){
queue<int> q;
deg[root]=0;
fa[root][0]=root;
q.push(root);
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=1;i<maxd;i++){
fa[u][i]=fa[fa[u][i-1]][i-1];
}
for(auto v:edg[u]){
if(v==fa[u][0])continue;
deg[v]=deg[u]+1;
fa[v][0]=u;
q.push(v);
}
}
}
int jump(int u,int det){
for(int i=0;det;det>>=1,i++){
if(det&1)u=fa[u][i];
}
return u;
}
int main(){
int t;
//cin>>t;
//while(t--){
int n,m;
cin>>n>>m;
for(int i=1,u,v;i<n;i++){
cin>>u>>v;
edg[u].push_back(v);
edg[v].push_back(u);
}
bfs(1);
while(m--){
int k;
cin>>k;
for(int i=0;i<k;i++)cin>>vi[i];
int x=1;
for(int i=0;i<k;i++){
if(deg[fa[vi[i]][0]]>deg[x])x=fa[vi[i]][0];
}
//cout<<"x:"<<x<<"\n";
bool flag=true;
for(int i=0;i<k;i++){
if(jump(x,deg[x]-deg[fa[vi[i]][0]])!=fa[vi[i]][0]){
flag=false;
break;
}
}
puts(flag?"YES":"NO");
}
//}
return 0;
}
F - Make k Equal
题意: \(n\)个数的数组\(a\),每次操作可以将某个最大值-1或者某个最小值+1.问操作几次使得至少存在\(k\)个相等的数字。
题解: 我们假设\(k\)个相等的数字都是\(i\),只有先将所有小于\(i\)的数字变为\(i-1\)或者所有大于\(i\)的数字变为\(i+1\)才能够操作成\(i\)。所以我们只要把\(a\)排序后维护一个前缀和和一个后缀和。计算出前缀变成\(i-1\)和后缀变成\(i+1\)的次数就可以简单的计算出答案。扫描一遍取最小值即可。细节看代码(最大值会超过0x3f3f3f3f。。。挂了一发)。
Accept Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
const ll inf=0x3f3f3f3f3f3f3f3f;
int a[maxn];
set<ll> st;
map<ll,ll> mp;
int main() {
int n,k;
cin>>n>>k;
ll suml=0,sumr=0,cntl=0,cntr=n;
for(int i=0;i<n;i++)cin>>a[i],sumr+=a[i],st.insert(a[i]),mp[a[i]]++;
sort(a,a+n);
ll res=inf;
for(auto i:st){
if(mp[i]>=k){
cout<<"0\n";
return 0;
}
sumr-=mp[i]*i;
cntr-=mp[i];
ll cnt=k-mp[i];
ll l=cntl*(i-1)-suml,r=sumr-cntr*(i+1);
if(cntl>=cnt)res=min(res,l+cnt);
if(cntr>=cnt)res=min(res,r+cnt);
res=min(res,l+r+cnt);
suml+=mp[i]*i;
cntl+=mp[i];
}
cout<<res<<"\n";
return 0;
}