Codeforces Round #629 (Div. 3)

A-Divisibility Problem

B-K-th Beautiful String

写的时候居然超时,哥们惊了,应该字符串用string的加法然后用cout<<string造成的,水题

C-Ternary XOR

从高位往低位看,如果当前位置是0,那么0=0+0
如果当前位置是2,那么当前位置是1+1=2,如果当前位置是1,那么让第一个数为1,另外一个数这一位为0,这样第一个数一定大于另外一个,后面的操作就是让第二数尽可能的大。

D-Carousel CodeForces

题意:一个环,环上编号从1-n,并且n和1相邻,每个位置会有一种动物,这个动物类型是ti,ti相同的表示为一种动物。要求对环染色,相邻的动物如果不同类型,那么颜色也应该不同,输出一种染色方法。
思路:如果是偶数的环,那么直接1-2-1-2就可以,如果是奇数的环,那么很简单,找到两个相同类型的动物,作为头和尾,染1-2-1-2,虽然最后出现1-1但是因为动物类型相同就可以,如果找不到就把最后用3代替。
代码

#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
using namespace std;
const int maxx = 2e5+6;
int a[maxx];
int main(){
    int t,n;
    #ifdef ONLINE_JUDGE
    #else
    freopen("in.txt","r",stdin);
    #endif
    scanf("%d",&t);
    while(t--){
    	scanf("%d",&n);
        int minn=2e5+6;
        int maxx=0;
        for (int i=0;i<n;i++){
        	scanf("%d",&a[i]);
            minn=min(minn,a[i]);
            maxx=max(maxx,a[i]);
        }
        if (minn==maxx){
        	printf("1\n");
        	for (int i=1;i<=n;i++){
        		printf("1 ");
        	}
        	printf("\n");
            continue;
        }
        if (n%2==0){
        	printf("2\n");
        	int flag=0;
        	for (int i=0;i<n;i++){
        		printf("%d ",flag+1);
        		flag=flag^1;
        	}
        	printf("\n");
        }else{
        	int pos=-1;
        	for (int i=0;i<n;i++){
        		//cout<<a[i]<<"-"<<a[(i+1)%n]<<endl;
        		if(a[i]==a[(i+1)%n]){
        			pos=i+1;
        			break;
        		}
        	}
        	if (pos==-1){
        		int flag=1;
        		printf("3\n");
        		for (int i=0;i<n-1;i++){
 					printf("%d ",flag+1);
 					flag=flag^1;
        		}
        		printf("3 ");
        		printf("\n");
        		
        		
        	}else {
        		int flag=0;
        		printf("2\n");
        		for (int i=0;i<n;i++){
        			if (i==pos){
        				flag=flag^1;
        			}
        			printf("%d ",flag+1);
        			flag=flag^1;
        		}
        		printf("\n");
        	}
        }
    }
	return 0;
}

E-Tree Queries

题意: 对于一棵树,是否能够找到从根到某个点的一条路径,使得询问的点和这条路的距离不超过1。
思路:我们可以通过BFS算出每个点的深度,然后在询问对时候,对这些点按照深度排序,我们检查相邻深度的点,是否满足相邻节点的LCA距离均大于1,如果满足就代表找不到,因为就出现了两个分叉深度均大于等于2的情况,不满足题意。
易错点: 写排序的时候注意加cmp函数
代码

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<queue>
using namespace std;
const int SIZE = 2e5+6;
int f[SIZE][30],d[SIZE];
int ver[2*SIZE],Next[2*SIZE],edge[2*SIZE],head[SIZE];
int T,n,m,tot,t;
queue<int>q;
int a[SIZE];
bool cmp(int x,int y){
	return d[x]<d[y];
}
void add(int x,int y){
	ver[++tot]=y;Next[tot]=head[x];head[x]=tot;
	ver[++tot]=x;Next[tot]=head[y];head[y]=tot;
}
void bfs(){
	q.push(1);
	d[1]=1;
	while(q.size()){
		int x=q.front();
		q.pop();
		for (int i=head[x];i;i=Next[i]){
			int y=ver[i];
			if (d[y])continue;
			d[y]=d[x]+1;
			f[y][0]=x;
			//由于是bfs,那么y点上面深度的点一定全部存在了
			for (int j=1;j<=t;j++)
				f[y][j]=f[f[y][j-1]][j-1];
			//这相当于(2^j-1)+(2^j-1)=2^j
			q.push(y);
		}
	}
}
int lca(int x,int y){
	if (d[x]>d[y])swap(x,y); //保证y深度大
	//把y深度从大往小找,类似与往上走的每次按照2的倍数去试,可以就往上,路径就是类似用二进制表示
	//一定能保证y跳到和x一样的深度
	for (int i=t;i>=0;i--)
		if (d[f[y][i]]>=d[x])y=f[y][i];
	if (x==y)return x;
	//然后像上面一样一起跳
	for (int i=t;i>=0;i--)
		if (f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
	//上面保证了f[x][i]!=f[y][i]
	//查到最后,一定就是父亲节点刚好是f[x][0]=f[y][0]
	return f[x][0];
}
int main(){
	int n,m;
	int uu,vv;
	#ifdef ONLINE_JUDGE
    #else
    freopen("in.txt","r",stdin);
    #endif
	while(~scanf("%d%d",&n,&m)){
		t=(int)(log(n)/log(2))+1;
		for (int i=1;i<=n-1;i++){
			scanf("%d%d",&uu,&vv);
			add(uu,vv);
		}
		bfs();
		while(m--){
			int num;
			scanf("%d",&num);
			int maxn=0;
			int p;
			for (int i=1;i<=num;i++){
				scanf("%d",&a[i]);
				if(d[a[i]]>maxn)
          	 	 {
               		 maxn=d[a[i]];
                	 p=a[i];
           		 }
			}
			int flag=0;
			for (int i=1;i<=num;i++){
				int lc=lca(a[i],p);
				if (lc!=a[i] && lc!=f[a[i]][0]){
				 	flag=1;
				 	break;
				}
			}
			if (flag){
				printf("NO\n");
			}else {
				printf("YES\n");
			}
		}
	}
	return 0;
}

F-Make k Equal

题意:给你1-n数字,你只能进行以下两个操作,1是把数组中最小的数字+1,2是把数组中最大是数组-1,问最少操作多少次使得数组中有k相同的数
思路:数学+前缀和
首先我们把所有数字排序,当把数组中第i个数作为出现k次的数
pre[i]前缀和,bac[i]后缀和
1首先考虑k个数全部是通过小的加上来
1.1当i<k: ia[i]-pre[i]代表把前i个数变到a[i]
1.2当i>jk: i
a[i]-pre[i]-(k-i)代表把前i个数变成k个a[i]
那么1.2显然可以作为答案的一种
2 考虑k个数全部是从大的减小过来
2.1 当n-i+1<k:bac[i]-(n-i+1)*a[i]代表把后i个数变到a[i]
2.2 当n-i+1>=k:bac[i]-(n-i+1)*a[i]-(n-k+1-i)代表把后k个数变成a[i]
显然2.2也是答案的一种
考虑答案是通过1+2组合而成的,那么1+2显然是把n个数字移动到a[i]所需的操作数目,但是我们只需要k个,所以把1和2的答案加起来再减去(n-k)即可
三个答案取最小值即可

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<queue>
#define LL long long
using namespace std;
const int maxx = 2e5+6;
LL a[maxx];
LL pre[maxx];
LL bac[maxx];
int main()
{
	int k,n;
	#ifdef ONLINE_JUDGE
    #else
    freopen("in.txt","r",stdin);
    #endif
	while(~scanf("%d%d",&n,&k)){
		for (int i=1;i<=n;i++){
			scanf("%lld",&a[i]);
		}
		sort(a+1,a+1+n);
		pre[0]=0;
		for (int i=1;i<=n;i++){
			pre[i]=pre[i-1]+a[i];
		}
		bac[n+1]=0;
		for (int i=n;i>=1;i--){
			bac[i]=bac[i+1]+a[i];
		}
		LL ans=1e18;
		int max_cnt=0;
		int cnt=1;
		for (int i=1;i<=n;i++){
			if (i!=1 && a[i]==a[i-1]){
				cnt++;
			}else {
				cnt=1;
			}
			max_cnt=max(max_cnt,cnt);
		}
		if (max_cnt>=k){
			printf("0\n");
			continue;
		}
		for (LL i=1;i<=n;i++){
			LL l=i*a[i]-pre[i];
			LL r=bac[i]-(n-i+1)*a[i];
			//cout<<l<<"-"<<r<<endl;
			if (i>=k){
				ans=min(ans,l-(i-k));
			}
			if (n-i+1>=k){
				ans=min(ans,r-(n-i+1-k));
			}
			ans=min(ans,l+r-(n-k));
		}
		printf("%lld\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值