题目 | 质数之谜
第九届中国大学生程序设计竞赛(秦皇岛)-(CCPC2023-Qinhuangdao)
F - 质数之谜
https://cpc.csgrandeur.cn/csgoj/problemset/problem?pid=1229
1 second / 256 megabytes
standard input / standard output
题目
数学王国的质数部长是质数的狂热追随者,因此他特别设立了一个部门来解决与质数相关的问题。这个部门的负责人罗伯特先生最近收到了他的朋友欧拉的一封信。
这封信中包含了一个关于质数的谜题。欧拉认为序列
形式化地说,
有时,欧拉信中给定的序列并不美丽。罗伯特先生希望通过修改最少数量的序列元素使其变得美丽。
罗伯特先生最近很忙,所以他想请你帮忙计算使序列变得美丽的最小修改数量。
输入
第一行包含一个整数
第二行包含
输出
输出一个整数,表示使序列变得美丽的最小更新元素数量。
样例
输入
6
1 5 1 4 4 1
输出
2
输入
9
30 6 7 12 15 8 20 17 14
输出
4
解释
对于第一个测试,更新后的序列可以是 “1 2 1 1 4 1”。
题解
孪生素数猜想 / 波利尼亚克猜想
首先介绍一下本题需要用到的重要猜想——孪生素数才行:存在无穷多个素数
波利尼亚克拓展了范围:对于所有自然数
猜想应用
除了偶素数
另外,根据上面的猜想,如果
因此,如果对于序列第
动态规划
因为
状态表示:
考虑 区间,且第 位为 状态所需最小步数。 :第 位不改 :第 位改成 :第 位改成偶数 :第 位改成奇数(除 )
状态计算:
:当且仅当 为素数时可转移 :当且仅当 为素数时可转移 :当且仅当 为奇数时可转移 :当且仅当 为偶数时可转移 :当且仅当 为素数时可转移 :恒可转移( 恒为素数) :恒可转移 :不可转移(奇 + 不可能为素数) :当且仅当 为奇数时可转移 :恒可转移 :不可转移(偶 + 偶 不可能为素数) :恒可转移 :当且仅当 为偶数时可转移 :不可转移( + 奇 不可能为素数) :恒可转移 :不可转移(奇 + 奇 不可能为素数)
通过上面的转移方式,转移时取最小值即可。对于初值,
时间复杂度为:
转移后,最终答案为:
代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
constexpr int MAXN = 2e5 + 10;
int prime[MAXN], idx;
bool not_prime[MAXN];
int n;
int a[MAXN];
int dp[MAXN][4];
void init_prime()
{
not_prime[0] = not_prime[1] = true;
for (int i = 2; i < MAXN; i++)
{
if (!not_prime[i])
prime[idx++] = i;
for (int j = 0; j < idx && i * prime[j] < MAXN; j++)
{
not_prime[i * prime[j]] = true;
if (i % prime[j] == 0)
break;
}
}
}
void solve()
{
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
memset(dp, 0x3f, sizeof(dp));
dp[1][0] = 0;
dp[1][1] = dp[1][2] = dp[1][3] = 1;
for (int i = 2; i <= n; i++)
{
// 0 -> 0
if (!not_prime[a[i - 1] + a[i]])
dp[i][0] = min(dp[i][0], dp[i - 1][0]);
// 1 -> 0
if (!not_prime[1 + a[i]])
dp[i][0] = min(dp[i][0], dp[i - 1][1]);
// 2 -> 0
if (a[i] % 2)
dp[i][0] = min(dp[i][0], dp[i - 1][2]);
// 3 -> 0
else
dp[i][0] = min(dp[i][0], dp[i - 1][3]);
///////////////////////////////////////////////
// 0 -> 1
if (!not_prime[a[i - 1] + 1])
dp[i][1] = min(dp[i][1], dp[i - 1][0] + 1);
// 1 -> 1
dp[i][1] = min(dp[i][1], dp[i - 1][1] + 1);
// 2 -> 1
dp[i][1] = min(dp[i][1], dp[i - 1][2] + 1);
// 3 -> 1: illegal
///////////////////////////////////////////////
// 0 -> 2
if (a[i - 1] % 2)
dp[i][2] = min(dp[i][2], dp[i - 1][0] + 1);
// 1 -> 2
dp[i][2] = min(dp[i][2], dp[i - 1][1] + 1);
// 2 -> 2: illegal
// 3 -> 2
dp[i][2] = min(dp[i][2], dp[i - 1][3] + 1);
///////////////////////////////////////////////
// 0 -> 3
if (a[i - 1] % 2 == 0)
dp[i][3] = min(dp[i][3], dp[i - 1][0] + 1);
// 1 -> 3: illegal
// 2 -> 3
dp[i][3] = min(dp[i][3], dp[i - 1][2] + 1);
// 3 -> 3: illegal
}
cout << min({dp[n][0], dp[n][1], dp[n][2], dp[n][3]}) << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
init_prime();
int t = 1;
// cin >> t;
while (t--)
solve();
return 0;
}
本文采用 CC BY-SA 4.0 许可,本文 Markdown 源码:Haotian-BiJi