质数(prime)

题目大意

给出 T T T 组询问,每组询问形如 n , K n,K n,K

求满足下面条件的 i i i 的个数:

  1. 1 ≤ i ≤ n 1 \leq i \leq n 1in
  2. ∀ 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 1j 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 1n1018,1K16

解题思路

对于 K ≤ 7 K \leq 7 K7 的情况,考虑容斥,时间复杂度 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 1j7,xmodpj=0 的数的个数。

因为,若一个数 x x x 不是 ∀ 1 ≤ i ≤ p , a i \forall 1 \leq i \leq p,a_i 1ip,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 1ip,ai 的倍数。

反之,若一个数 x x x 不是 ∀ 1 ≤ i ≤ p , a i \forall 1 \leq i \leq p,a_i 1ip,ai 的倍数,则 k x kx kx 不是 ∀ 1 ≤ i ≤ p , a i \forall 1 \leq i \leq p,a_i 1ip,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[5105101]+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(2K7)

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值