目录
涵盖知识点:思维、构造、树上倍增。
比赛链接:传送门
博客园目录好像不能用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
";continue;}
if(a<=b)cout<<b-a<<"
";
else cout<<b-(a%b)<<"
";
}
return 0;
}
B - K-th Beautiful String
题意: 长度为(n)的字符串包含(n-2)个a和(2)个b,求按照字典序排列的第(k)个。
题解: 观察样例,左边的b的位置出现次数按照(1,2,3ldots)排列,确定后再确定右边的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<<"
";
}
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<<"
"<<b<<"
";
}
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
";
for(int i=1;i<=n;i++)cout<<1<<" ";
cout<<"
";
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
";
for(int i=1;i<n;i++)cout<<i%2+1<<" ";
cout<<"3
";
}
else{
cout<<"2
";
if(!(n&1)){
for(int i=1;i<=n;i++)cout<<i%2+1<<" ";
cout<<"
";
}else{
for(int i=1;i<pos;i++)cout<<i%2+1<<" ";
for(int i=pos;i<=n;i++)cout<<2-i%2<<" ";
cout<<"
";
}
}
}
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<<"
";
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
";
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<<"
";
return 0;
}