歐拉函式——簽到題
- 題目
- 演算法分析
- Code
- 總結與反思
題目
Luogu:P3601 簽到題
演算法分析
題中 我們定義一個函式: q i a n d a o ( x ) qiandao(x) qiandao(x)為小于等于x的數中與 x x x不互質的數的個數 讓我們很自然地想到 歐拉函式 ,那就在這里先介紹一下這個神奇的函式,
數論基礎——歐拉函式
學習完之后我們勾回頭來看這道題,題中的
q
i
a
n
d
a
o
(
x
)
qiandao(x)
qiandao(x) 其實就是求
(
p
h
i
(
x
)
(phi(x)
(phi(x)表示x的歐拉函式
)
)
)
∑
i
=
l
r
(
i
?
p
h
i
(
i
)
)
\sum_{i=l}^{r} ( i-phi(i) )
i=l∑r?(i?phi(i))
我們定睛一看發現這道題的資料有點大,但兩端點之間的區間相對較小,于是考慮對區間進行處理并掃描統計即可,先篩出
1
0
6
10^{6}
106中所有的質數,然后對
[
l
,
r
]
[l,r]
[l,r]區間進行處理,
具體代碼見下
Code
#include<iostream>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define rg register
#define ll long long
using namespace std;
const int P=666623333;
const int MAXN=1000001;
ll prime[MAXN];
int isprime[MAXN];
ll l,r,cnt,ans;
ll phi[MAXN];
ll n[MAXN];
void iprime()
{
for(rg int i=2;i<=MAXN;++i)
{
if(!isprime[i])
prime[++cnt]=i;
for(rg int j=2*i;j<=MAXN;j+=i)
{
isprime[j]=1;
}
}
}
void getphi()
{
int i=1;
while(prime[i]*prime[i]<=r)
{
for(rg int x=(prime[i]-l%prime[i])%prime[i];x<=r-l;x+=prime[i])
{
phi[x]=phi[x]/prime[i]; phi[x]=phi[x]*(prime[i]-1);
while(n[x]%prime[i]==0)
{
n[x]/=prime[i];
}
}
i++;
}
}
int main()
{
iprime();
scanf("%lld %lld",&l,&r);
for(rg ll i=l;i<=r;++i)
{
phi[i-l]=i; n[i-l]=i;
}
getphi();
for(rg ll i=0;i<=r-l;++i)
{
if(n[i]!=1)
{
phi[i]/=n[i];phi[i]*=(n[i]-1);
}
ans=(ans+(i+l-phi[i])%P)%P;
}
printf("%lld\n",ans);
return 0;
}
總結與反思
1.
1.
1.資料太大想辦法處理,如本題可轉化成區間長度掃描,
2.
2.
2.學習理解歐拉函式,要掌握一些常用的板子,
3.
3.
3.要學會對資料范圍進行分析,根據不同的資料范圍選擇不同的演算法,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/256302.html
標籤:其他
上一篇:怎么和小伙伴語音連麥,你造嗎?
