数论专题R1(线性筛专题)

这篇博客详细介绍了线性筛在数论问题中的应用,包括反素数加强版的解决方案,约数积函数的计算,函数h(n)和g(n)的定义及实现,以及涉及的数学概念。博客通过实例和代码解释了如何使用线性筛优化算法,达到线性时间复杂度,并给出了相关问题的解题思路和代码示例。
摘要由CSDN通过智能技术生成

目录

A 反素数加强版

B 约数积函数

C h(n)

D g(n)                                                          

E 神必的函数

F 球与盒子 

总结

A 反素数加强版

时空限制

1s,32MB

问题描述

     如果一个大于等于1的正整数n,满足所有小于n且大于等于1的所有正整数的约数个数都小于n的约数个数,则n是一个反素数。请你计算不大于n的最大反素数。

输入格式

第一行输入数据组数T,每组数据输入1个正整数n。 

输出格式

对每组数据,输出不大于n的最大反素数。 

数据范围

1<=T<=100,1<=n<=1e18。

 思路

       由数据范围可得时间复杂度为O(T+log(n))。

       对于n=p1^r1*p2^r2*...*pk^rk(p为质数&&r>=1)的约数个数为(r1+1)*(r2+1)*...*(rk+1)。 

       又因为前15个质数之积大于1e18,所以只用dfs枚举前15个质数头上的指数,并将它们组合起来即可。

        优化(剪枝):对于题目要求的n,rx>=ry(x<=y),即更小质数头上的指数一定小于等于更大质数头上的指数。感性理解,如果我在3的指数上加一,为什么不在2头上加一个呢,这样ans一样而且目前的数还要小一点,后面添加的东西还会更多一点。

代码

        我加了个__int128,但是可以通过tp<n/p[num]来实现。

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
#include<stack>
#define int __int128
using namespace std;
long long t,n;
long long p[]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
struct node{
	int cnt1,ans1;
}ans;
void dfs(long long num,long long r,int cnt,int sum,long long lr)
{	
	if(r>lr)return;
	__int128 tp=sum*(long long)pow(p[num],r);
	if(tp*p[num]>n)
	{
		if(ans.cnt1<cnt*(r+1)||((ans.cnt1==cnt*(r+1))&&(ans.ans1>tp)))
		{
			ans.cnt1=cnt*(r+1),ans.ans1=tp;
		}
	}
	if(tp*p[num]<=n)
	{
		dfs(num,r+1,cnt,sum,lr);
	}
	if(tp*p[num+1]<=n&&num<=14)
	{
		dfs(num+1,0,cnt*(r+1),tp,r);
	}
}
void w(__int128 x)
{
	if(x<0)
	{
		putchar('-');
		x=-x;
	}
	if(x>9)w(x/10);
	putchar(x%10+'0');
}
signed main()
{
	scanf("%lld",&t);
	while(t--)
	{
		scanf("%lld",&n);
		dfs(1,0,1,1,100);
		w(ans.ans1);
		printf("\n");
		ans.ans1=0,ans.cnt1=0;
	}
	return 0;
}

注释:num:现在枚举到第几个质数。

           r:现在枚举到的质数头上的指数。

           cnt:除开现在枚举到的指数外,总数的因数个数。

           sum:除开现在枚举到的指数外的总数。

           lr:上一个质数的指数。

B 约数积函数

时空限制

1s,256MB

问题描述

约数积函数\pi(n),表示n的所有约数的乘积。

输入格式

第一行输入数据组数T,对每组数据:

输入一个整数 n。

输出格式

对每组数据,输出一个整数,表示\pi(n)对1e9+7取模。  

数据范围

1<=T<=1e5,1<=n<=1e7 。

思路

        看数据可知时间复杂度为O(n+T)。

        因为约数是俩俩成对的,所以我们只需要算出它有多少对约数即可。然后判断它是不是完全平方数。  很6呀!

        问题是怎么算约数个数?

        这就要请出R1的关键算法欧拉筛(线性筛)了。

        欧拉筛模板:      

void ol(int N)
{
    for(int i=2;i<N;i++)
	{
		if(f[i]==0)p[++idx]=i;
		for(int j=1;j<=idx&&i*p[j]<N;j++)
		{
			f[i*p[j]]=1;
			if(i%p[j]==0)break;
		}
	}
}

        它之所以是线性的,是因为每个数只被筛到一次且只会被它的最小质因子筛到

        所以可以将枚举的i分为两类,一类是已经有p[j]这个质因子(if(i%p[j]==0)),一类没有(else)。

        我们设r[i]表示i最小质因子的指数,d[i]表示i的因数个数

        可推得:

                当i%p[j]==0时:

                        r[i*p[j]]=r[i]+1,d[i*p[j]]=d[i]/(r[i]+1)*(r[i]+2)

                         分析(p[j]即为p1

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值