Problem: J . Palindromic Primes
记录个模板。
题目大意:
求
L
L
L 到
R
R
R 之间既是素数又是回文数的个数。
解题思路:
数据范围
1
e
12
1e12
1e12。一般的前缀和做法解决不了。分析一下,对于一个回文数,都可以按位拆分成两部分。例如
123321
123321
123321,可以拆分为
123
123
123 和
321
321
321 ,对于奇数位的整数12321,可以拆分为
123
123
123 和
21
21
21,事实上,我们只要知道前半部分,后半部分就可以求出来,然后将前后两部分再凑到一起,判断其是否是素数即可。这样一来,对于庞大的
1
e
12
1e12
1e12 的范围,我们只需要枚举前
1
e
6
1e6
1e6个数,就可以将
1
e
12
1e12
1e12 内所有的回文整数找出来了。
接下来只剩下判断素数了,怎样快速判断一个较大的数是否是素数呢?这里用到了一个稀奇古怪的算法米勒拉宾算法。
这里我就直接借模板一用啦。
AcCoding:
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
ll qmul(ll a, ll b, ll p)
{
ll c = (long double)a / p * b;
ll res = (ull)a * b - (ull)c * p;
return (res + p) % p;
}
ll qpow(ll x, ll y, ll p)
{
ll res = 1;
while (y) {
if (y & 1) res = qmul(res, x, p);
x = qmul(x, x, p);
y >>= 1;
}
return res;
}
bool isprime(ll x)
{
if (x < 3) return x == 2;
if (!(x & 1)) return false;
ll A[] = { 0, 2, 325, 9375, 28178, 450775, 9780504, 1795265022 };
ll d = x - 1, r = 0;
while (d % 2 == 0)
{
r++;
d /= 2;
}
for (auto a : A)
{
ll v = qpow(a, d, x);
if (v <= 1 || v == x - 1) continue;
for (int i = 1; i <= r; i++)
{
v = qmul(v, v, x);
if (v == x - 1 && i != r)
{
v = 1;
break;
}
if (v == 1)
return false;
}
if (v != 1)
return false;
}
return true;
}
void get(ll x,ll& sum1,ll& sum2) {
vector<int> v;
while (x) {
v.push_back(x % 10);
x /= 10;
}
sum1 = 0;
sum2 = 0;
//123
reverse(v.begin(), v.end());
for (int i = 0;i < v.size();i++) sum1 = sum1 * 10ll + v[i], sum2 = sum2 * 10ll + v[i];
for (int i = v.size() - 2;i >= 0;i--) sum1 = sum1 * 10ll + v[i];
for (int i = v.size() - 1;i >= 0;i--) sum2 = sum2 * 10ll + v[i];
}
int main() {
ll l, r; scanf("%lld%lld", &l, &r);
ll res = 0;
for (ll i = 1;i <= 1000000;i++) {
ll x, y;
x = y = 0;
get(i, x, y);
if (min(x, y) > r) break;
if (x >= l && x <= r && isprime(x)) res++;
if (y >= l && y <= r && isprime(y)) res++;
}
printf("%lld", res);
return 0;
}