数论-容斥原理 Cirno的完美算数教室

先暴力找出由 2, 9 组成的 <= R 的数字存到 P ,排序并去除满足 gcd(i, j) > 1 的一对 (i, j) 中的较大数得到 Pu(ique)

由容斥原理计算 [L, R] 含有 Pu 中至少一个约数的数的个数. 由于 Pu 中约数数量较大,二进制枚举子集法不可用,

所以写了个搜索来枚举。

当 R = 10^10 时, Pu = 681, 不太大,所以不会超时(如果这都超时那就脱鞋吧(划掉))。

 1 #include <stdio.h>
 2 #include <math.h>
 3 #include <algorithm>
 4 
 5 using namespace std;
 6 
 7 typedef long long LL;
 8 
 9 const int _N = 4000;
10 
11 LL P[_N], Pu[_N];
12 LL mx_bit, L, R, Pcnt, Pucnt, ans;
13 
14 void _dfs(LL bit, LL v)
15 {
16     if (bit > mx_bit || v > R) return;
17     
18     if (bit) P[++Pcnt] = v;
19     
20     _dfs(bit+1, v*10 + 2), _dfs(bit+1, v*10 + 9);
21     return;
22 }
23 
24 LL _gcd(LL t1, LL t2) { return t2 ? _gcd(t2, t1%t2) : t1; }
25 
26 void _lalala(LL t1, LL t2, LL mul)
27 {
28     if (t1 == Pucnt+1) {
29         if (t2&1)
30             ans += R/mul - (L-1)/mul;
31         else if (t2) ans -= R/mul - (L-1)/mul;
32         return;
33     }
34     _lalala(t1+1, t2, mul);
35     mul = mul / _gcd(mul, Pu[t1]) * Pu[t1];
36     if (mul <= R) _lalala(t1+1, t2+1, mul);
37     return;
38 }
39 
40 int main()
41 {
42     LL i, j;
43     scanf("%lld%lld", &L, &R);
44     mx_bit = log(R+0.5)/log(10) + 1;
45     _dfs(0, 0);
46     sort(P+1, P+1+Pcnt);
47     for (i = 1; i <= Pcnt; ++i) {
48         if (!P[i]) continue;
49         Pu[++Pucnt] = P[i];
50         for (j = i+1; j <= Pcnt; ++j)
51             if (P[j] && !(P[j] % P[i])) P[j] = 0;
52     }
53 //    Pucnt = 681 and Pcnt = 2046 when R = 10^10
54     ans = 0;
55     _lalala(1, 0, 1);
56     printf("%lld
", ans);
57     return 0;
58 }
View Code

题目:NKOJ4046

P4046Cirno的完美算数教室
时间限制 : - MS   空间限制 : 165536 KB 
评测说明 : 1s
问题描述

~Cirno发现了一种baka数,这种数呢~只含有2和9两种数字~~
现在Cirno想知道~一个区间中~~有多少个数能被baka数整除~
但是Cirno这么天才的妖精才不屑去数啦
只能依靠聪明的你咯。

输入格式

一行正整数L R
( 1 < L < R < 10^10)

输出格式

一个正整数,代表所求的答案

样例输入

1 100

样例输出

58

原文地址:https://www.cnblogs.com/ghcred/p/8463424.html