題目大意
給出 \(T\) 組詢問,每組詢問形如 \(n,K\)。
求滿足下面條件的 \(i\) 的個數:
- \(1 \leq i \leq n\)。
- \(\forall_{1 \leq j \ leq K},i \bmod p_j \ne 0\)。
\(p_j\) 表示第 \(j\) 大的質數。
對於 \(100\%\) 的數據,\(1 \leq n \leq 10^{18},1 \leq K \leq 16\)。
解題思路
對於 \(K \leq 7\) 的情況,考慮容斥,時間復雜度 \(\mathcal O(2^K)\)。
對於 \(K > 7\) 的情況,記 \(cnt_i\) 表示 \([1,i]\) 中的一個數 \(x\) 滿足 \(\forall_{1 \leq j \leq 7},x \bmod p_j \ne 0\) 的數的個數。
因為,若一個數 \(x\) 不是 \(\forall 1 \leq i \leq p,a_i\) 的倍數,當且僅當 \(x \bmod Lcm(a)\) 不是 \(\forall 1 \leq i \leq p,a_i\) 的倍數。
反之,若一個數 \(x\) 不是 \(\forall 1 \leq i \leq p,a_i\) 的倍數,則 \(kx\) 不是 \(\forall 1 \leq i \leq p,a_i\) 的倍數,\(k \ne 0\)。
\(n \ 的 \ ans=\left\lfloor n/510510 \right\rfloor \ ∗ \ cnt[510510 - 1]+cnt[n \bmod 510510]\)。
接下來用 \(cnt\) 容斥即可,這個容斥是建立在 \([1,n]\) 中的數都不是前 \(7\) 個質數的基礎上進行容斥的,時間復雜度 \(\mathcal O(2^{K-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;
}