Codeforces Round #629 (Div. 3)【ABCDEF】(题解)
[toc]
涵盖知识点:思维、构造、树上倍增。
比赛链接:传送门
博客园目录好像不能用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;
}