【洛谷 P9420】[蓝桥杯 2023 国 B] 子 2023 / 双子数 题解(动态规划+欧拉筛法+暴力枚举+提交答案)

[蓝桥杯 2023 国 B] 子 2023 / 双子数

题目描述

A 子 2023

小蓝在黑板上连续写下从 1 1 1 2023 2023 2023 之间所有的整数,得到了一个数字序列:

S = 12345678910111213 ⋯ 20222023 S = 12345678910111213\cdots 20222023 S=1234567891011121320222023

小蓝想知道 S S S 中有多少种子序列恰好等于 2023 2023 2023

提示,以下是 3 3 3 种满足条件的子序列(用中括号标识出的数字是子序列包含的数字):

1 [ 2 ] 34567891 [ 0 ] 111 [ 2 ] 1 [ 3 ] 14151617181920212223 ⋯ 1[\textbf2]34567891[\textbf0]111[\textbf2]1[\textbf3]14151617181920212223 \cdots 1[2]34567891[0]111[2]1[3]14151617181920212223

1 [ 2 ] 34567891 [ 0 ] 111 [ 2 ] 131415161718192021222 [ 3 ] ⋯ 1[\textbf2]34567891[\textbf0]111[\textbf2]131415161718192021222[\textbf3] \cdots 1[2]34567891[0]111[2]131415161718192021222[3]

1 [ 2 ] 34567891 [ 0 ] 111213141516171819 [ 2 ] 021222 [ 3 ] ⋯ 1[\textbf2]34567891[\textbf0]111213141516171819[\textbf2]021222[\textbf3] \cdots 1[2]34567891[0]111213141516171819[2]021222[3]

注意以下是不满足条件的子序列,虽然包含了 2 2 2 0 0 0 2 2 2 3 3 3 四个数字,但是顺序不对:

1 [ 2 ] 345678910111 [ 2 ] 131415161718192 [ 0 ] 21222 [ 3 ] ⋯ 1[\textbf2]345678910111[\textbf2]131415161718192[\textbf0]21222[\textbf3] \cdots 1[2]345678910111[2]131415161718192[0]21222[3]

B 双子数

若一个正整数 x x x 可以被表示为 p 2 × q 2 p^2 \times q^2 p2×q2,其中 p p p q q q 为质数且 p ≠ q p \neq q p=q,则 x x x
一个 “双子数”。请计算区间 [ 2333 , 23333333333333 ] [2333, 23333333333333] [2333,23333333333333] 内有多少个 “双子数”?

输入格式

输入一个大写字母,表示第几个问题。

输出格式

根据所输入的问题编号,输出对应问题的答案。

提示

答题模板,可供参考。

#include<iostream>
using namespace std;
int main() {
    string ans [] = {
        "The answer of task A", // 双引号中替换为 A 题的答案
        "The answer of task B", // 双引号中替换为 B 题的答案
    };
    char T;
    cin >> T;
    cout << ans[T - 'A'] << endl;
    return 0;
}

第十四届蓝桥杯大赛软件赛决赛 C/C++ 大学 B 组 A、B 题


思路

如果输入的字符是’A’,则执行solve1()函数解决子2023问题,否则执行solve2()函数解决双子数问题。

在solve1()函数中,首先创建一个字符串s,将1到2023的所有整数转换为字符串并连接起来。然后,使用动态规划的方法来找出所有子序列等于"2023"的数量。dp[i]存储的是当前字符串中"2023"的前i个字符的子序列的数量。然后遍历字符串s,如果当前字符与"2023"的某个字符相同,就将dp[j]增加dp[j-1],这样就可以累计计算出所有子序列等于"2023"的数量。

在solve2()函数中,首先使用欧拉筛法找出所有小于等于sqrt(maxi)的质数,并将其存储在pri数组中。然后,计算所有质数的平方,并将结果存储在p2数组中。接着,遍历p2数组,找出所有满足条件的双子数(即可以表示为两个不同质数的平方的乘积,并且在给定的区间内)。


AC代码

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

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

ll dp[15];
string s = " ";
string target = " 2023";

bitset<N> vis;
ll pri[N];
int cnt = 0;
ll p2[N];

void solve1() {
	memset(dp, 0, sizeof(dp));

	for (int i = 1; i <= 2023; i++) {
		s += to_string(i);
	}
	int len = s.length() - 1;
	// cout << s << endl;

	dp[0] = 1;
	for (int i = 1; i <= len; i++) {
		for (int j = 1; j <= 4; j++) {
			if (s[i] == target[j]) {
				dp[j] += dp[j - 1];
			}
		}
	}
	cout << dp[4] << "\n";
}

void solve2() {
	ll mini = 2333;
	ll maxi = 23333333333333;
	int sm = sqrt(maxi);
	for (int i = 2; i <= sm; i++) {
		if (!vis[i]) {
			pri[cnt++] = i;
		}
		for (int j = 0; j < cnt && i * pri[j] <= sm; j++) {
			vis[i * pri[j]] = 1;
			if (i % pri[j] == 0) {
				break;
			}
		}
	}

	for (int i = 0; i < cnt; i++) {
		p2[i] = 1LL * pri[i] * pri[i];
	}

	ll ans = 0;
	for (int i = 0; i < cnt; i++) {
		if (p2[i] * p2[i] > maxi) {
			break;
		}
		for (int j = i + 1; j < cnt; j++) {
			ll p2q2 = p2[i] * p2[j];
			if (mini > p2q2) {
				continue;
			}
			if (maxi < p2q2) {
				break;
			}
			ans++;
		}
	}
	cout << ans << endl;
}

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

	if (getchar() == 'A') {
		solve1();
	} else {
		solve2();
	}
	return 0;
}
  • 17
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值