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

125 阅读1分钟

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

题目描述

A 子 2023

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

S=1234567891011121320222023S = 12345678910111213\cdots 20222023

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

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

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

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

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

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

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

B 双子数

若一个正整数 xx 可以被表示为 p2×q2p^2 \times q^2,其中 ppqq 为质数且 pqp \neq q,则 xx 是 一个 “双子数”。请计算区间 [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;
}