LibreOJ - 6235 区间素数个数(min25筛)

题目链接:点击这里

题目大意:
给定一个数 n n n ,求 1 1 1 n n n 的质数个数

题目分析:
阉割版 m i n 25 min25 min25
不妨令完全积性函数 F ( x ) = 1 F(x)=1 F(x)=1
然后做 s ( n , j ) s(n,j) s(n,j) 的转移
由于 f ( p k ) = 0 f(p^k)=0 f(pk)=0 ,所以合数贡献就可以不算了,故求得的 s ( n , 0 ) s(n,0) s(n,0) 就是所求答案

具体细节见代码:

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
#define ll long long
#define inf 0x3f3f3f3f
#define Inf 0x3f3f3f3f3f3f3f3f
#define int  ll
#define endl '\n'
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
using namespace std;
int read()
{
	int res = 0,flag = 1;
	char ch = getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch == '-') flag = -1;
		ch = getchar();
	}
	while(ch>='0' && ch<='9')
	{
		res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
		ch = getchar();
	}
	return res*flag;
}
const int maxn = 1e6+5;
//const int mod = 1e9+7;
const int mod = Inf; 
const double pi = acos(-1);
const double eps = 1e-8;
int n,cnt,pri[maxn],sp1[maxn],sp2[maxn],sq;
int w[maxn],tot,id1[maxn],id2[maxn],g[maxn];
bool vis[maxn];
void get_pri(int n)
{
	for(int i = 2;i <= n;i++)
	{
		if(!vis[i])
		{
			pri[++cnt] = i;
			sp1[cnt] = (sp1[cnt-1]+1)%mod;
			sp2[cnt] = (sp2[cnt-1]+i*i%mod)%mod;
		}
		for(int j = 1;j <= cnt && i*pri[j] <= n;j++)
		{
			vis[i*pri[j]] = true;
			if(i%pri[j] == 0) break;
		}
	}
}
int qpow(int a,int b)
{
	int res = 1;
	while(b)
	{
		if(b&1) res = res*a%mod;
		a = a*a%mod;
		b >>= 1;
	}
	return res;
}
const int inv2 = qpow(2,mod-2),inv6 = qpow(6,mod-2);
ll S(int i,int j)
{
	if(pri[j] >= i) return 0;
	ll pos = i<=sq ? id1[i] : id2[n/i];
	ll res = (g[pos]-j)%mod; //质数部分贡献 
//  f(p^k)=0所以不计合数贡献 
//	for(int k = j+1;k<=cnt && pri[k]*pri[k]<=i;k++) //合数部分贡献 
//	{
//		ll pe = pri[k];
//		for(int e = 1;pe <= i;e++,pe = pe*pri[k]) //不能取模 
//		{
//			ll x = pe%mod;
//			res = (res+x*(x-1)%mod*(S(i/pe,k)+(e>1))%mod)%mod;
//		} 
//	}
	return res;
}
signed main()
{
	n = read(); sq = sqrt(n);
	get_pri(sq);
	for(int l = 1,r;l <= n;l = r+1)
	{
		r = min(n,n/(n/l));
		w[++tot] = n/l%mod; //取余方便计算下述的g(n,0) 
		g[tot] = (w[tot]-1+mod)%mod; //减一是为了减去第一项,因为 1 不是质数 
		w[tot] = n/l;
		if(w[tot] <= sq) id1[w[tot]] = tot;
		else id2[n/w[tot]] = tot;
	}
	for(int j = 1;j <= cnt;j++) //g(n,j)
		for(int i = 1;i<=tot && pri[j]*pri[j]<=w[i];i++)
		{
			ll tmp = w[i]/pri[j];
			ll pos = tmp <= sq ? id1[tmp] : id2[n/tmp];
			g[i] = (g[i]-(g[pos]-(j-1)+mod)%mod+mod)%mod;
		}
	printf("%lld\n",(S(n,0))%mod);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值