【WOJ 4240】約數個數
【題目】
題目描述:
給出整數 ,求它的約數個數
為了加大難度,有 次詢問,將每次詢問的答案求和然後模
輸入格式:
第一行是一個整數
第二行是整數 , , ,
表示第一次詢問的數字
第 次詢問
輸出格式:
所有詢問的答案之和模
樣例資料:
輸入
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;
}