【洛谷 P8615】[蓝桥杯 2014 国 C] 拼接平方数 题解(字符串+集合+数学)

[蓝桥杯 2014 国 C] 拼接平方数

题目描述

小明发现 49 49 49 很有趣,首先,它是个平方数。它可以拆分为 4 4 4 9 9 9,拆分出来的部分也是平方数。 169 169 169 也有这个性质,我们权且称它们为:拼接平方数。

100 100 100 可拆分 1 , 00 1,00 1,00,这有点勉强,我们规定, 0 , 00 , 000 0,00,000 0,00,000 等都不算平方数。

小明想:还有哪些数字是这样的呢?

你的任务出现了:找到某个区间的所有拼接平方数。

输入格式

两个正整数 a , b ( a < b < 1 0 6 ) a,b(a<b<10^6) a,b(a<b<106)

输出格式

若干行,每行一个正整数。表示所有的区间 [ a , b ] [a,b] [a,b] 中的拼接平方数,从小到大输出。

样例 #1

样例输入 #1

169 10000

样例输出 #1

169
361
1225
1444
1681
3249
4225
4900
9025

提示

时限 1 秒, 256M。蓝桥杯 2014 年第五届国赛


思路

首先定义两个集合sqans,其中sq用来保存平方数,ans用来保存满足条件的拼接平方数。然后从输入中读取两个数ab,这两个数定义了需要查找的区间。

接着,进行预处理,计算所有小于等于b的平方数,将结果保存到集合sq中。这里使用了sqrt(b)来限定循环的上界,减少了不必要的计算。

在预处理完毕后,开始遍历集合sq,对于每一个元素,将其转换为字符串s1,然后再次遍历集合sq,将元素转换为字符串s2。在这个过程中,尝试将s1s2进行拼接,并将结果转换为整数c

如果c大于b,则终止当前循环,因为后续的拼接结果都会大于b。如果c在区间[a, b]内,并且c是平方数(即sq集合中存在c),则将c添加到集合ans中。

在这个过程中,s2会不断地在前面添加0,直到拼接结果的长度超过8时停止循环,防止出现std::out_of_range的错误。

最后,遍历集合ans,将其中的元素按照升序输出,这就是所有满足条件的拼接平方数。


AC代码

#include <algorithm>
#include <cmath>
#include <iostream>
#include <set>
#define AUTHOR "HEX9CF"
using namespace std;
using ll = long long;

const int N = 1e6 + 7;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;

int n;
set<int> sq, ans;

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	int a, b;
	cin >> a >> b;

	for (int i = 1; i <= sqrt(b); i++) {
		sq.insert(i * i);
		// cout << i * i << endl;
	}

	for (auto it1 = sq.begin(); it1 != sq.end(); it1++) {
		string s1 = to_string(*it1);
		for (auto it2 = sq.begin(); it2 != sq.end(); it2++) {
			string s2 = to_string(*it2);
			while (1) {
				string s = s1 + s2;
				// cout << s << endl;
				if (s.length() > 8) {
					// 防止std::out_of_range
					break;
				}
				int c = stoi(s);
				if (c > b) {
					break;
				}
				if (c >= a && c <= b && sq.count(c)) {
					// cout << *it1 << " " << *it2 << " " << c << endl;
					ans.insert(c);
				}
				// 第二个平方数可以有前导零
				s2 = "0" + s2;
			}
		}
	}

	for (const auto i : ans) {
		cout << i << "\n";
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值