题目链接:点击查看
题目大意:求解:
题目分析:我们需要提前知道威尔逊定理:如果p是素数,则
所以我们可以分情况讨论:
- 当3k+7是素数时,,因为威尔逊定理,,所以一定是一个整数,我们设为x,这样一来后面的,因为一定小于等于1,所以取整后一定是x-1,这样一来f(k)=1
- 当3k+7不是素数时,(3k+6)!一定能被(3k+7)整除(显然成立),然后上述公式就转换成了,所以f(k)=0
综上所述,先用欧拉线性筛打一个3e6的素数表,因为3k+7最大能到3e6+7,然后预处理一个前缀和,就可以O(1)回答每一个查询了
代码:
#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
const int N=1e7+100;
int cnt=0;
bool vis[N];
int pri[N];
int sum[N];
void P()
{
memset(vis,false,sizeof(vis));
for(int i=2;i<N;i++)
{
if(!vis[i])
pri[cnt++]=i;
for(int j=0;j<cnt&&pri[j]*i<N;j++)
{
vis[pri[j]*i]=true;
if(i%pri[j]==0)
break;
}
}
memset(vis,false,sizeof(vis));
for(int i=0;i<cnt;i++)
vis[pri[i]]=true;
}
void init()
{
P();
sum[0]=0;
for(int i=1;i<1e6+10;i++)
{
sum[i]=sum[i-1];
if(vis[3*i+7])
sum[i]++;
}
}
int main()
{
// freopen("input.txt","r",stdin);
init();
int w;
cin>>w;
while(w--)
{
int n;
scanf("%d",&n);
printf("%d\n",sum[n]);
}
return 0;
}