题目大意
给出 T T T 组询问,每组询问形如 n , K n,K n,K。
求满足下面条件的 i i i 的个数:
- 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n。
- ∀ 1 ≤ j l e q K , i m o d p j ≠ 0 \forall_{1 \leq j \ leq K},i \bmod p_j \ne 0 ∀1≤j leqK,imodpj=0。
p j p_j pj 表示第 j j j 大的质数。
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 18 , 1 ≤ K ≤ 16 1 \leq n \leq 10^{18},1 \leq K \leq 16 1≤n≤1018,1≤K≤16。
解题思路
对于 K ≤ 7 K \leq 7 K≤7 的情况,考虑容斥,时间复杂度 O ( 2 K ) \mathcal O(2^K) O(2K)。
对于 K > 7 K > 7 K>7 的情况,记 c n t i cnt_i cnti 表示 [ 1 , i ] [1,i] [1,i] 中的一个数 x x x 满足 ∀ 1 ≤ j ≤ 7 , x m o d p j ≠ 0 \forall_{1 \leq j \leq 7},x \bmod p_j \ne 0 ∀1≤j≤7,xmodpj=0 的数的个数。
因为,若一个数 x x x 不是 ∀ 1 ≤ i ≤ p , a i \forall 1 \leq i \leq p,a_i ∀1≤i≤p,ai 的倍数,当且仅当 x m o d L c m ( a ) x \bmod Lcm(a) xmodLcm(a) 不是 ∀ 1 ≤ i ≤ p , a i \forall 1 \leq i \leq p,a_i ∀1≤i≤p,ai 的倍数。
反之,若一个数 x x x 不是 ∀ 1 ≤ i ≤ p , a i \forall 1 \leq i \leq p,a_i ∀1≤i≤p,ai 的倍数,则 k x kx kx 不是 ∀ 1 ≤ i ≤ p , a i \forall 1 \leq i \leq p,a_i ∀1≤i≤p,ai 的倍数, k ≠ 0 k \ne 0 k=0。
n 的 a n s = ⌊ n / 510510 ⌋ ∗ c n t [ 510510 − 1 ] + c n t [ n m o d 510510 ] n \ 的 \ ans=\left\lfloor n/510510 \right\rfloor \ ∗ \ cnt[510510 - 1]+cnt[n \bmod 510510] n 的 ans=⌊n/510510⌋ ∗ cnt[510510−1]+cnt[nmod510510]。
接下来用 c n t cnt cnt 容斥即可,这个容斥是建立在 [ 1 , n ] [1,n] [1,n] 中的数都不是前 7 7 7 个质数的基础上进行容斥的,时间复杂度 O ( 2 K − 7 ) \mathcal O(2^{K-7}) O(2K−7)。
CODE
#include <bits/stdc++.h>
using namespace std;
#define int unsigned long long
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
inline void write(int x)
{
if(x < 0)
{
putchar('-');
x = -x;
}
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
int T, n, k;
int cnt[510517], cnta[1 << 7 | 1], cntb[1 << 9 | 1];
const int kkk = 510510;
int prime[] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59};
int ans;
void init()
{
int S = 1 << 7;
for(int i = 0; i < S; ++i)
{
cnta[i] = 1;
for(int j = 1; j <= 7; ++j)
if(i & (1 << (j - 1)))
cnta[i] *= prime[j];
}
for(int i = 1; i <= 7; ++i)
for(int j = 1; j * prime[i] <= kkk; ++j)
cnt[j * prime[i]] = 1;
for(int i = 1; i < kkk; ++i)
cnt[i] = cnt[i - 1] + (1 - cnt[i]);
S = 1 << 9;
for(int i = 0; i < S; ++i)
{
cntb[i] = 1;
for(int j = 1; j <= 9; ++j)
if(i & (1 << (j - 1)))
cntb[i] *= prime[j + 7];
}
}
int __cnt(int x)
{
int k = 0;
for(int i = x; i; i -= (i & -i))
k++;
return k;
}
signed main()
{
init();
T = read();
while(T--)
{
n = read(), k = read();
ans = 0;
if(k <= 7)
{
int S = 1 << k;
for(int i = 0; i < S; ++i)
{
if(__cnt(i) & 1)
ans -= n / cnta[i];
else
ans += n / cnta[i];
}
}
else
{
int S = 1 << (k - 7);
for(int i = 0; i < S; ++i)
{
int p = n / cntb[i];
int now = (p / kkk) * cnt[kkk - 1] + cnt[p % kkk];
if(__cnt(i) & 1)
ans -= now;
else
ans += now;
}
}
write(ans);
putchar('\n');
}
return 0;
}