質數(prime)


題目大意

給出 \(T\) 組詢問,每組詢問形如 \(n,K\)

求滿足下面條件的 \(i\) 的個數:

  1. \(1 \leq i \leq n\)
  2. \(\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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM