【WOJ 4240】约数个数

【题目】

题目描述:

给出整数 x x ,求它的约数个数

为了加大难度,有 m m 次询问,将每次询问的答案求和然后模 1 0 9 + 7 10^9+7

输入格式:

第一行是一个整数 m m

第二行是整数 q 1 q_1 a a b b c c

q 1 q_1 表示第一次询问的数字

i i 次询问 q i = ( q i 1 a + b ) % c q_i=(q_{i−1}∗a+b)\%c

输出格式:

所有询问的答案之和模 1 0 9 + 7 10^9+7

样例数据:

输入
2
2 2 1 9

输出
4

提示:

100 % 100\% 的数据保证 m 3 × 1 0 6 , a , b , c 1 0 7 , q i 1 , c 1 m\leq 3\times 10^6, a,b,c\leq10^7,q_i≥1,c≥1


【分析】

看到这道题的数据范围, q q 1 0 7 10^7 级别的,所以应该是 O ( n ) O(n) 的复杂度

然后打了个暴力,去看正解,发现是用线性筛来筛约数个数,然后就学了一下

首先,新定义两个数组 g[i]num[i]g[i] 表示 i i 的约数个数,num[i] 表示 i i 最小质因数的个数

举个例子,对于 12g[12]=6num[12]=2(因为 12=2*2*3)

有一个结论,如果把一个数分解成 p 1 a 1 p 2 a 2 p k a k p_1^{a_1}\cdot p_2^{a_{2}}\cdots p_{k}^{a_k} ,那么一个数的约数个数应为 i = 1     k ( a i + 1 ) \prod ^{\;\,k}_{i=1}(a_i+1)

现在分三种情况讨论一下:

1、若 i 为质数,那么显然 g[i]=2,num[i]=1

2、若 i 为合数

由于在线性筛中,一个数只会被它的最小质因数和除它以外的最大因数筛掉,那么就设这个最小质因数为 p p ,这个因数为 x x

1)若 x x p p 的倍数,此时 p p 就是 i i x x 的最小质因数,也即若把 x x 表示成 (num[x]+1)*k k k 为其他的质因个数 +1 的乘积), i i 就可以表示成 (num[x]+2)*k

\therefore 此时, g[i]=g[x]/(num[x]+1)*(num[x]+2),num[i]=num[x]+1

2)若 x x 不为 p p 的倍数,因为 p p i i 的最小质因数,所以易知 num[i]=1,并且 i i 相当于只是在 x x 的基础上多乘了一个 p p ,所以 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;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/84887559
今日推荐