CF Round 1072 A~D 题解

CF Round 1072 题解

A

签到题。

题目大意

$ n $ 个人被分成若干组,每组 2~3 个人,每组作为一个整体从两个课题中选一个,问最后选两个课题的人数之差最小值。

分析

最开始以为是 DP,但想了想后一个 \(n\) 的最优状态不一定是由 \(n-1\) 推出来的。

发现当 \(n \geqslant 4\) 时,总能凑出两个课题选择人数为 \(\lceil \frac{n}{2} \rceil\)\(\lfloor \frac{n}{2} \rfloor\) 的组,于是只与其奇偶性有关。

代码

//#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
//#include<algorithm>
using namespace std;
//const int N=10000;
void work(){
	int n;
	scanf("%d",&n);
	if(n<=3){
		printf("%d\n",n);
		return;
	}
	printf("%d\n",n&1);
	return;
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--)work();
}

B

题目大意

瓦迪姆的沙漏能计时 \(s\) 分钟。每 \(k\) 分钟他会翻转一次沙漏,无论沙漏是否漏完。

从第零分钟沙漏开始流动,问他第 \(m\) 分钟外出(不再翻转沙漏)后沙漏还能漏几分钟。

分析

本来以为将 \(m\)\(k\) 取模再用 \(s\) 去减就行,之后发现我是 sb。

每两次翻转才会将沙漏的状态初始化,所以应当对 \(k\times2\) 取模才对。

然后就是简单的分类讨论。

代码

//#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
//#include<algorithm>
using namespace std;
//const int N=10000;
void work(){
	int s,k,m;
	scanf("%d%d%d",&s,&k,&m);
	m%=k*2;
	if(m>=k){
		printf("%d\n",max(0,min(s,k)-(m-k)));
	}else{
		printf("%d\n",max(0,s-m));
	}
}
int main(){
	int t;
	scanf("%d",&t);
	while(t--)work();
}

C

题目大意

给你两个数 \(n\)\(k\) ,每次你能够将 \(n\) 分为 \(\lceil \frac{n}{2} \rceil\)\(\lfloor \frac{n}{2} \rfloor\) 的两个部分,并令其中一个部分为新的 \(n\) ,问使 \(n=k\) 至少需要多少次上述操作。

分析

发现将这个问题转为二进制处理会很简单。

操作转变为 “每次将n的最后一个二进制位抹去,如果该位为 1 ,则可以在抹去后的 \(n\) 的最后一位上加 1 .

于是只需要比较 \(n\) 的最高几位是否与 \(k\) 或者 \(k+1\) 相同就行,然后就是一些关于进位的繁琐处理。

代码

//#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
//#include<algorithm>
using namespace std;
//const int N=10000;
int bitcount(int k){
	int ans=0;
	while(k){
		ans++;
		k>>=1;
	}
	return ans;
} 
void work(){
	int n,k;
	scanf("%d%d",&n,&k);
	if(k>n){
		printf("-1\n");
		return;
	}
	if(k==n){
		printf("0\n");
		return;
	}
	int cn=bitcount(n);
	int ck=bitcount(k);
	if((n>>(cn-ck))==k){
		printf("%d\n",cn-ck);
		return;
	}
	if((n>>(cn-ck))+1==k){
		if(cn>ck){
			if(((n>>(cn-ck))<<(cn-ck))!=n){
				printf("%d\n",cn-ck);
				return;
			}
		}
	}
	if(((n>>(cn-ck+1))+1)==k){
		if(((n>>(cn-ck+1))<<(cn-ck+1))!=n){
			printf("%d\n",cn-ck+1);
			return;
		}
	}
	printf("-1\n");
	return;
}
int main(){
//	printf("%d",(3>>1)<<1);
	int t;
	scanf("%d",&t);
	while(t--)work();
}
 

D

题目大意

Bob 给出一个数 \(a\) ,Alice 知道这个数的奇偶性。Alice 每次操作可以使 \(a\) 减 1 或者除以 2 。

Alice 操作后 Bob 会接着告诉他一个数 x ,表示 \(a\) 能被 \(2^{x}\) 整除却不能被 \(2^{x+1}\) 整除。

问 1~n 中,Alice 需要至少 \(k+1\) 次操作才能把这个数变成 0 的数有多少个。

分析

这次很快想到了二进制位运算。

发现对于某个数,将其二进制位末尾的 0 抹去的代价是 1 次操作,而末尾的 1 抹去的代价是 2 次操作。

于是一个数 \(a\) 的代价为\(\log_{2}a+1+bitcount(a)\)

发现对于位数相同的 \(a\) 可以用组合数计算数量。

对于靠着上界 \(n\)\(a\) ,似乎可以容斥计算。

代码

最后 30 分钟燃尽了没写出来。


这是入 zex 的队后的第二次康复训练。

能感觉自己明显没有高二的时候强了,但目前的水平放大一的 OIer 里还算是能看得过去。

希望别成为拖后腿的那个。

posted @ 2026-01-22 11:27  Liyanx_ArtI  阅读(3)  评论(0)    收藏  举报