CF988D题解

文章讲述了如何利用编程解决一个关于数列的问题,即在给定的n个数字中找到最多能组成多少个数对,其差值为2的幂。通过枚举和集合数据结构,作者展示了如何确定序列长度为1、2或3的情况并提供了AC代码示例。

题目大意

题目传送门

题意:给你有 n n n 个数字的一个数列,问最多有多少个数字他们 两两的差是 2 的幂次方数

思路

首先,我们想个数能不能组成一个满足题目要求的序列,答案是肯定的。(直接输出 a 1 a_1 a1 不就彳亍了吗)

再想个数彳亍不彳亍。看看样例:

输入 #1

6
3 5 4 7 10 12

输出 #1

3
7 3 5

举个栗子: 3 3 3 5 5 5 之间差距是 2 2 2,即 2 1 2^1 21

再来看个数的,样例输出就已经给了。

个数,还是举个栗子:

输入:
1 2 3 4

发现如果是个数, 1 1 1 4 4 4 相差 3 3 3,并不是 2 2 2 的次方,发现不行。

证明一下:

令四个数为 a , b , c , d a,b,c,d a,b,c,d,则:

∣ a − b ∣ = 2 x 0 , ∣ b − c ∣ = 2 x 1 , ∣ c − d ∣ = 2 x 2 |a-b|=2^{x_0}, |b-c|=2^{x_1}, |c-d|=2^{x_2} ab=2x0,bc=2x1,cd=2x2

此时需要满足两两之差为 2 2 2 的次方,则 x 0 = x 1 = x 2 x_0=x_1=x_2 x0=x1=x2

∣ a − c ∣ = 2 x 0 + 1 , ∣ b − d ∣ = 2 x 1 + 1 |a-c|=2^{x_0+1}, |b-d|=2^{x_1+1} ac=2x0+1,bd=2x1+1

∣ a − d ∣ = 3 × 2 x 0 ≠ 2 k |a-d|=3 \times 2^{x_0} \ne 2^k ad=3×2x0=2k

所以,可以满足题目要求的序列的元素个数只能输 1 , 2 , 3 1, 2, 3 1,2,3 个。

代码核心部分:

for (int i = 1;i <= n;i++) //枚举3个数组成的序列 
{
	for (int j = 0;j <= 30;j++)
	{
		int w = sum[j]; //w获取了2的j次方
		if (s.count(a[i]+w) >= 1 && s.count(a[i]+2*w) >= 1) //判断是否有一个满足条件的序列 
		{
			printf("3\n%lld %lld %lld",a[i],a[i]+w,a[i]+2*w); //可以输出啦 
			return 0; //直接结束程序 
		}
	}
}

最后,附上我的 AC 代码:

#include <bits/stdc++.h> //万能头 
#define int long long //可能会超int 
using namespace std;
int n;
int a[200010];
set <int> s; //用集合去存储,会自动去重和排序 
int sum[40]; //sum[i]表示2的i次方 
signed main() //这里注意是signed 
{
	sum[0] = 1; //这里初始化是为了优化pow函数 
	for (int i = 1;i <= 30;i++)
	{
		sum[i] = sum[i-1] * 2;
	}
	scanf("%lld",&n); //以防万一,就用scanf吧 
	for (int i = 1;i <= n;i++)
	{
		scanf("%lld",&a[i]);
		s.insert(a[i]); //将a[i]加入集合 
	}
	for (int i = 1;i <= n;i++) //枚举3个数组成的序列 
	{
		for (int j = 0;j <= 30;j++)
		{
			int w = sum[j]; //w获取了2的j次方
			if (s.count(a[i]+w) >= 1 && s.count(a[i]+2*w) >= 1) //判断是否有一个满足条件的序列 
			{
				printf("3\n%lld %lld %lld",a[i],a[i]+w,a[i]+2*w); //可以输出啦 
				return 0; //直接结束程序 
			}
		}
	}
	for (int i = 1;i <= n;i++) //枚举2个数组成的序列
	{
		for (int j = 0;j <= 30;j++)
		{
			int w = sum[j]; //w获取了2的j次方
			if (s.count(a[i]+w) >= 1) //判断是否有一个满足条件的序列 
			{
				printf("2\n%lld %lld",a[i],a[i]+w); //可以输出啦 
				return 0; //直接结束程序 
			}
		}
	}
	printf("1\n%lld",a[1]); //最后,如果3个或2个都不行,那就随便输出原数列中的一个数 
	return 0;
}
要查找 Codeforces 比赛的题解,可以通过以下方法实现: ### 方法一:通过官方博客或社区获取题解 许多比赛结束后,Codeforces 官方会发布一篇博客文章,其中可能包含题目解析和作者的想法。这些博客通常由出题人撰写,提供了权威的解答方式[^1]。 访问 Codeforces 主页后,在首页新闻部分寻找对应的比赛总结博文,点击进入阅读即可获得详细的题解说明[^2]。 ### 方法二:利用他人撰写的公开题解资源 一些参赛者会在个人博客或其他平台上分享他们对于某场比赛的理解与解决办法。例如: - **Linno** 提供了关于 `Codeforces Round #759` 和 `Educational Codeforces Round 125` 的详细中文版题解[^3]。 - 类似地,还有其他博主针对不同轮次的比赛提供了解析文档[^4]。 可以直接搜索具体场次编号加上关键词“editorial”或者“solution”,找到对应的第三方解读材料。 ### 方法三:直接查阅AC代码学习思路 如果无法快速定位到文字形式的题解,还可以借助已通过测试的数据来反向推导算法逻辑。按照如下步骤操作: 1. 找到目标问题页面; 2. 转至“Status”标签下查看所有提交记录; 3. 使用过滤器仅显示状态为“Accepted”的解决方案,并选择一种熟悉的编程语言版本研究其核心实现细节[^5]。 以下是简单演示如何抓取并分析一段C++程序片段作为例子: ```cpp #include <bits/stdc++.h> using namespace std; int main(){ int n; cin >> n; string s[n]; for(auto &x:s)cin>>x; bool flag=false; for(int i=0;i<n && !flag;i++) for(int j=i+1;j<n && !flag;j++) if(s[i]==s[j]){ cout<<"YES"; flag=true; } if(!flag)cout<<"NO"; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值