【题目】
题目描述:
给出整数 ,求它的约数个数
为了加大难度,有 次询问,将每次询问的答案求和然后模
输入格式:
第一行是一个整数
第二行是整数 , , ,
表示第一次询问的数字
第 次询问
输出格式:
所有询问的答案之和模
样例数据:
输入
2
2 2 1 9
输出
4
提示:
的数据保证 。
【分析】
看到这道题的数据范围, 是 级别的,所以应该是 的复杂度
然后打了个暴力,去看正解,发现是用线性筛来筛约数个数,然后就学了一下
首先,新定义两个数组 g[i] 和 num[i],g[i] 表示 的约数个数,num[i] 表示 最小质因数的个数
举个例子,对于 12,g[12]=6,num[12]=2(因为 12=2*2*3)
有一个结论,如果把一个数分解成 ,那么一个数的约数个数应为
现在分三种情况讨论一下:
1、若 i 为质数,那么显然 g[i]=2,num[i]=1
2、若 i 为合数
由于在线性筛中,一个数只会被它的最小质因数和除它以外的最大因数筛掉,那么就设这个最小质因数为 ,这个因数为
(1)若 为 的倍数,此时 就是 和 的最小质因数,也即若把 表示成 (num[x]+1)*k( 为其他的质因个数 +1 的乘积), 就可以表示成 (num[x]+2)*k
此时, g[i]=g[x]/(num[x]+1)*(num[x]+2),num[i]=num[x]+1
(2)若 不为 的倍数,因为 是 的最小质因数,所以易知 num[i]=1,并且 相当于只是在 的基础上多乘了一个 ,所以 g[i]=g[x]*2
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 10000005
#define Mod 1000000007
using namespace std;
int prime[N],g[N],num[N];
bool mark[N];
void linear_sieves()
{
int i,j,sum=0;
memset(mark,true,sizeof(mark));
mark[0]=mark[1]=false;g[1]=1;
for(i=2;i<N;++i)
{
if(mark[i])
{
g[i]=2;
num[i]=1;
prime[++sum]=i;
}
for(j=1;j<=sum&&i*prime[j]<N;++j)
{
mark[i*prime[j]]=false;
if(i%prime[j]==0)
{
num[i*prime[j]]=num[i]+1;
g[i*prime[j]]=g[i]/(num[i]+1)*(num[i]+2);
break;
}
num[i*prime[j]]=1;
g[i*prime[j]]=g[i]*2;
}
}
}
int main()
{
linear_sieves();
int m,i,a,b,c,now;
scanf("%d%d%d%d%d",&m,&now,&a,&b,&c);
int ans=g[now];
for(i=2;i<=m;++i)
{
now=(1ll*now*a+b)%c;
ans=(ans+g[now])%Mod;
}
printf("%d",ans);
return 0;
}