容斥
Pty hates prime numbers
当k小于8的时候直接容斥
当k大于8的时候先预处理一下1~8
x不是前k个质数的倍数 <=> x%(p1*p2*...pk)不是前k个质数的倍数
于是可以求出任意n时不能被1到8整除的数的个数
在对9~16进行容斥的时候:
例如能被31整除的数为31(1,2,3,4,…m)因为31不能被1到8整除所以只要知道1~m有几个数不能被整除就行了。
容斥的时候每一步都把能被1~8个素数整除的都去掉就行了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = (1<<16)+10;
const ll inf = 1e18+100;
const ll mod = 9699690;
ll prime[20] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
ll s[N],num[mod+10];
int main(){
for(int i = 1;i<(1<<16);i++){
ll cur = 1;
for(int j = 0;j<=15;j++){
if((1<<j)&i){
if(inf/prime[j] < abs(cur)){
cur = -1;
break;
}
else{
cur *= (-prime[j]);
}
}
}
s[i] = cur;
}
num[0] = 0;
for(ll i = 1;i<=mod;i++){
for(int j = 0;j<=7;j++){
if((i%prime[j]) == 0){
num[i]++;
break;
}
}
if(num[i] == 0) num[i] = num[i-1]+1;
else num[i] = num[i-1];
}
int T;
cin >> T;
while(T--){
ll n;int k;
cin >> n >> k;
if(k<=8){
ll ans = n;
for(int j = 1;j<(1<<k);j++){
if(s[j] == -1) continue;
ans += n/s[j];
}
cout << ans << endl;
}
else{
ll ans = (n/mod)*num[mod]+num[n%mod];
for(int j = 1;j<(1<<(k-8));j++){
if(s[j] == -1) continue;
if(s[j] > 0){
ans += ((n/s[(j<<8)])/mod)*num[mod]+num[(n/s[(j<<8)])%mod];
}
else{
ans -= ((n/(-s[(j<<8)]))/mod)*num[mod]+num[(n/(-s[(j<<8)]))%mod];
}
}
cout << ans << endl;
}
}
return 0;
}