Skip to content

S2OJ - 1539. 报数

题解约 1 千字
检测到 KaTeX 加载失败,可能会导致文中的数学公式无法正常渲染。

#题面

#题目描述

一天,小 L 和小 W 在玩一个报数游戏。两人约定只能报出质数,即因数只有 11 和它自身的数。特别的,11 不被视作质数。然而,在只有两个人的情况下,找到质数还是很容易的,因此他们玩了很久也没分出胜负。此时,小 L 灵光一闪,决定把这个游戏加强:报出的数不仅要是质数,还要满足它的各位数字之和也是一个质数!

例如,3131 不是一个满足条件的数,因为虽然它本身是一个质数,但它的各位数字之和为 44,不是一个质数;3434 不是一个满足条件的数,因为虽然它的个位数字之和为 77,是一个质数,但它本身并不是一个质数;4141 是一个满足条件的数,因为不仅它本身是一个质数,它的各位数字之和 55 也是一个质数。

现在小 L 想要集中精力报出 [L,R][L, R] 之间的满足条件的数,因此他会询问你范围内满足条件的数的个数是多少。小 L 和小 W 一共会玩 TT 次游戏,而你也要回答 TT 个问题。

为了减少输入输出量,小 L 对输入输出的方式进行了一些处理。

#输入格式

第一行一个整数 TT,表示小 LL 询问的数量。

第二行五个整数 L,R,a,b,cL, R, a, b, c,表示第一个询问的范围为 [L,R][L, R],对于第 iii2i ≥ 2)个询问,该次询问的范围 L,RL, R 与上次询问的范围 L0,R0L_0, R_0 满足如下关系:

x=(L0b+a) mod c+1x = (L_0 ⊕ b + a) \bmod c + 1y=(R0b+a)mod c+1y = (R_0 ⊕ b + a) \mod c + 1,则 L=min(x,y)L = \min(x, y)R=max(x,y)R = \max(x, y)

其中 表示二进制下按位异或运算。

#输出格式

一行一个整数,表示每组询问的答案的异或和。

#输入输出样例

样例输入 #1

2
2 9 1 0 20

样例输出 #1

7

样例解释

对于第一次询问,满足条件的数有 2,3,5,72, 3, 5, 7

对于第二次询问,询问的范围是 [4,11][4, 11],满足条件的数有 5,7,115, 7, 11

两次询问答案的异或和为 43=74 ⊕ 3 = 7

样例 #2

见下发文件中的 number2.innumber2.out

该样例满足测试点 8108 \sim 10 的数据范围和限制。

#数据范围

对于所有数据,满足 1T,a,b,c1071 ≤ T, a, b, c ≤ 10^71LR1071 ≤ L ≤ R ≤ 10^7

测试点编号 TT \leq L,R,cL, R, c \leq
121 \sim 2 1010 10410^4
343 \sim 4 10510^5
575 \sim 7 10710^7
8108 \sim 10 10710^7

#思路

先筛出所有质数,再从中筛出各位数字之和为质数的数,最后暴力求出每个询问的答案的前缀和即可。

#代码

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <iostream>
#include <algorithm>

using std::cin;
using std::cout;
const char endl = '\n';

int t, l, r, a, b, c, ans;
int p, cnt, primes[10000005], sum[10000005];
bool not_prime[10000005];

inline bool check(int x) {
int sum = 0;

while (x) {
sum += x % 10;
x /= 10;
}

return !not_prime[sum];
}

int main() {
std::ios::sync_with_stdio(false);
cin.tie(nullptr);

for (int i = 2; i <= 10000000; i++) {
if (!not_prime[i]) primes[++p] = i;

for (int j = 1; j <= p && primes[j] * i <= 10000000; j++) {
not_prime[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}

for (int i = 1; i <= 10000000; i++) {
if (!not_prime[i] && check(i)) sum[i] = sum[i - 1] + 1;
else sum[i] = sum[i - 1];
}

cin >> t >> l >> r >> a >> b >> c;

while (t--) {
ans ^= sum[r] - sum[l - 1];

l = ((l ^ b) + a) % c + 1;
r = ((r ^ b) + a) % c + 1;
if (l > r) std::swap(l, r);
}

cout << ans << endl;

return 0;
}