当前位置: 首页 > news >正文

[GESP202312 五级] 平均分配

文章目录

  • 题目描述
  • 输入格式
  • 输出格式
  • 输入输出样例 #1
    • 输入 #1
    • 输出 #1
  • 输入输出样例 #2
    • 输入 #2
    • 输出 #2
  • 提交链接
  • 提示
  • 解析
  • 参考代码

题目描述

小杨认为,所有大于等于 a a a 的完全平方数都是他的超级幸运数。

小杨还认为,所有超级幸运数的倍数都是他的幸运数。自然地,小杨的所有超级幸运数也都是幸运数。

对于一个非幸运数,小杨规定,可以将它一直 + 1 +1 +1,直到它变成一个幸运数。我们把这个过程叫做幸运化。例如,如果 a = 4 a=4 a=4,那么 4 4 4 是最小的幸运数,而 1 1 1 不是,但我们可以连续对 1 1 1 3 3 3 + 1 +1 +1 操作,使其变为 4 4 4,所以我们可以说, 1 1 1幸运化后的结果是 4 4 4

现在,小杨给出 N N N 个数,请你首先判断它们是不是幸运数;接着,对于非幸运数,请你将它们幸运化。

输入格式

第一行 2 2 2 个正整数 a , N a, N a,N

接下来 N N N 行,每行一个正整数 x x x ,表示需要判断(幸运化)的数。

输出格式

输出 N N N 行,对于每个给定的 x x x ,如果它是幸运数,请输出 lucky,否则请输出将其幸运化后的结果。

输入输出样例 #1

输入 #1

2 4 
1 
4 
5 
9

输出 #1

4 
lucky 
8 
lucky

输入输出样例 #2

输入 #2

16 11 
1 
2 
4 
8 
16 
32 
64 
128 
256 
512
1024

输出 #2

16 
16 
16 
16 
lucky 
lucky 
lucky 
lucky 
lucky 
lucky 
lucky

提交链接

平均分配

提示

样例解释 1

虽然是完全平方数,但它小于 a a a,因此它并不是超级幸运数,也不是幸运数。将其进行 3 3 3 + 1 +1 +1 操作后,最终得到幸运数 4 4 4。4是幸运数,因此直接输出 lucky

5 5 5 不是幸运数,将其进行 3 3 3 + 1 +1 +1 操作后,最终得到幸运数 8 8 8

9 9 9 是幸运数,因此直接输出 lucky

数据规模

对于 30 % 30\% 30% 的测试点,保证 a , x ≤ 100 , N ≤ 100 a,x \le 100,N \le 100 a,x100,N100

对于 60 % 60\% 60% 的测试点,保证 a , x ≤ 1 0 6 a,x \le 10^6 a,x106

对于所有测试点,保证 a ≤ 1 , 000 , 000 a \le 1,000,000 a1,000,000;保证 N ≤ 2 × 1 0 5 N \le 2 \times 10^5 N2×105;保证 1 ≤ x ≤ 1 , 000 , 001 1 \le x \le 1,000,001 1x1,000,001

解析

此题的关键,找出:

  1. 找出所有超级幸运数:即大于等于 a a a 的完全平方数;

  2. 找出所有幸运数:所有超级幸运数及它们的倍数。

先考虑 30 % 30\% 30% 的数据。

此时的 a a a x x x 的最大范围为 100 100 100。我们可以暴力枚举一定范围,把这个范围内的完全平方数全部找到。 a ∼ 1000 a \sim 1000 a1000 这个范围一定是完全足够。

v i s [ ] vis[] vis[] 来标记幸运数
枚举完全平方数及其倍数

//判断一个数 是否为完全平方数
bool check(int x)
{
	int ave = sqrt(x);
	return ave * ave == x;
}

vector<int>ans;  //存储 1e3 范围内的幸运数字
//只考虑1e3的数据 看能过多少测试点
for(int i = a; i <= Mx; i++)
{
	if(check(i))
	{
		if(!vis[i])
		{
			ans.push_back(i);
			vis[i] = true;//考虑1e3范围内的超级幸运数的倍数
			int rate = 2;
			while(rate * i <= Mx)  //考虑超级幸运数的倍数 
			{
				if(!vis[rate * i])
				{
					ans.push_back(rate * i);
					vis[rate * i] = true;
				}
				rate++;
			}
		}
	}
}

对于输入的 n n n 个数 x x x。若被标记则输出lucky,否则我们可以根据二分找到第一个大于 x x x 的位置输出。

sort(ans.begin() , ans.end());  //从小到大排序
for(int i = 1; i <= n; i++)
{
	if(vis[x[i]])
		cout << "lucky" << endl;
	else
	{
		int pos = upper_bound(ans.begin() , ans.end() , x[i]) - ans.begin();
		cout << ans[pos] << endl;

	}

}

对于 100 % 100\% 100% 的数据。
a ≤ 1 , 000 , 000 a \le 1,000,000 a1,000,000 1 ≤ x ≤ 1 , 000 , 001 1 \le x \le 1,000,001 1x1,000,001

最极端的情况, x x x 1000001 1000001 1000001 a a a 1000000 1000000 1000000,若没有倍数的情况,大于 a a a 的最小的完全平方数为 1002001 1002001 1002001

我们可以借助 30 % 30\% 30% 数据的思路,对代码进行优化,分析时间复杂度。

平方数从 s q r t ( a ) sqrt(a) sqrt(a) 开始,最大的范围到 1002001 ( 1001 ∗ 1001 = 1002001 ) 1002001(1001 * 1001 = 1002001) 1002001(10011001=1002001)

for (int i = ceil(sqrt(a)); i <= 1001; i++)

对于每一个完全平方数我们依然选出其倍数进行存储。

// 能得出当x=1000001 最差的幸运数为1002001,1002001为完全平方数
for (int i = ceil(sqrt(a)); i <= 1001; i++)
{
	int x = i * i; // x为完全平方数
	for (int j = 1; j * x <= 1002001; j++)
	{
		if (!vis[x * j])   //超级幸运数的倍数
		{
			ans.push_back(x * j);
			vis[x * j] = true;
		}
	}
}

此题的难点在于分析时间复杂度,考虑上述预处理代码的时间复杂度:

遍历从 a a a u p = 1002001 up = 1002001 up=1002001

  • 如果 i i i 是完全平方数,就遍历它的所有倍数 j = i , 2 i , 3 i , . . . , u p j = i, 2i, 3i, ..., up j=i,2i,3i,...,up,时间为 O ( u p / i ) O(up / i) O(up/i)

一共操作的次数: ∑ i 2 ≥ a u p u p i 2 \sum_{i^2≥a}^{\sqrt{up}} \frac{up}{i^2} i2aup i2up

化简后,求和为一个收敛常数,时间复杂度大约为 1 e 6 1e6 1e6 级别。

预处理后,对于每一个数 判断标记 + 二分 进行输出。

参考代码

#include <bits/stdc++.h>
using namespace std;

bool vis[1100000];

int main()
{
    int a, n;
    cin >> a >> n;

    vector<int> ans; // 存储幸运数字

    // 能得出当x=1000001 最差的幸运数为1002001,1002001为完全平方数
    for (int i = ceil(sqrt(a)); i <= 1001; i++)
    {
        int x = i * i; // x为完全平方数
        for (int j = 1; j * x <= 1002001; j++)
        {
            if (!vis[x * j])   //超级幸运数的倍数
            {
                ans.push_back(x * j);
                vis[x * j] = true;
            }
        }
    }
    sort(ans.begin() , ans.end());
    while (n--)
    {
        int x;
        cin >> x;
        if (vis[x])
            cout << "lucky" << endl;
        else
        {
            int pos = upper_bound(ans.begin(), ans.end(), x) - ans.begin();
            cout << ans[pos] << endl;
        }
    }
    return 0;
}

相关文章:

  • C语言今天开始了学习
  • 【python读取并显示遥感影像】
  • win日志
  • 仿真每日一练 | ABAQUS子程序DLOAD
  • 复杂物快速定性定量:液相色谱质谱联用仪
  • 7.第二阶段x64游戏实战-string类
  • 【MySQL基础】左右连接实战:掌握数据关联的完整视图
  • LabVIEW 中 JSON 数据与簇的转换
  • Java实战报错 tcp
  • 深入理解深度学习模型的训练与评估模式:从基础组件到实战应用
  • 【WRF理论第十七期】单向/双向嵌套机制(含namelist.input详细介绍)
  • The 2024 CCPC National Invitational Contest (Changchun),第17届吉林省赛 C
  • STM32 HAL库之EXTI示例代码
  • 线程池(一):线程基础知识全面解析
  • 独立部署及使用Ceph RBD块存储
  • 学习OpenCV C++版
  • 卡尔曼滤波器的工作原理
  • 嵌入式系统中如何构建事件响应架构
  • Droris(强制)删除某一个分区数据
  • 优先级队列的应用
  • 最牛视频网站建设/合肥优化排名推广
  • 做ppt到哪个网站找图片/鄞州seo服务
  • 华为云怎么做网站/app开发网站
  • 公司找人做网站/竞价网络推广培训
  • 企业网站源码 php/百度新闻发布平台
  • 哪个语言做动态网站好用/友情链接官网