類歐幾里得算法
擴展歐拉定理(對於a,p不互質的情況計算a%p):https://blog.csdn.net/hzj1054689699/article/details/80693756
二次剩餘
https://blog.csdn.net/kele52he/article/details/78897187
對於n整數a若存在整數x 滿足 x^2%n=a那麼稱a是mod n 的二次剩餘
判定:當且僅當 a^(p-1)/2=1
引理:對於奇素數p下的二次剩餘n,有兩個不同的x滿足x^2%p=n
一個奇素數的完全剩餘系下有(p-1)/2 個二次剩餘。
Cipolla 算法
求解 x^2=n mod p,。
步驟:
1.隨機一個 a,使得 ,期望次數 2 次。
2.令 ,擴域爲虛根。
3. 即爲所求。
//xy%p=xy-(xy)/p*p
inline ll qmul(ll a,ll b,ll mod)
{
a%=mod,b%=mod;
return (((a*b)-(ll)((ll)((long double)a/mod*b+1e-3)*mod))%mod+mod)%mod;
}
擴展BSGS
狄利克雷卷積的逆
。通過構造,可以 構造出函數的逆。
如果積性函數 和 對於任意質數 滿足 ,我們就可以快速求出 的前綴和。
設 ,那麼就有 ,推出 。
我們要求的是:
由於 只在所有質因子次數都大於 1 的情況下才不爲零,這樣的數可以寫成 的形式,不超過 個。枚舉 ,枚舉 ,就得到了 的質因數分解,即可快速計算。
狄利克雷生成函數
多項式卷積即爲狄利克雷卷積。
定義求導算子 :當 爲質數時,,對於整數 ,,有 。
1
求 。
??? ??? ???
min_25 篩
作用:計算積性函數前綴和。複雜度 。
要求: 爲關於 的低次多項式, 能很快計算。
第一步
我們想要求所有質數的函數值。考慮用質數把合數的貢獻篩掉。記 , 表示 的最小質因子。
初始,我們知道 的值,也就是一個自然數冪和(這就是要求 是一個低次多項式的原因)。因此我們按照 從小到大的順序轉移 。考慮 轉移到 ,有哪些數變得不合法了。就是那些最小質因子剛好爲 的那些數。
注意到,如果 如果大於 ,由於沒有小於 的合數含有 ,因此直接轉移過來。
第一維只有根號 大小。發現求 的過程與積性函數沒關係,因此可以求 到 質數個數。
第二步
考慮用這個東西求函數的前綴和。定義 。目標是求 ,邊界條件是 爲所有質數的答案。因此我們遞歸計算 。轉移的時候枚舉最小質因子,枚舉最小質因子 的次數 ,。注意單獨考慮 。
Loj6053 簡單的函數
Notice: 1 拿出來最後單獨統計,val 數組裏的值從大到小,數組開到兩倍根號。
#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define ld long double
using namespace std;
const int mod=1e9+7,M=200010,inv2=(mod+1)/2;
int ind1[M],ind2[M];
bool np[M];
ll sum[M],p[M],cnt,tot,h[M],g[M],val[M],n,B;
int read()
{
int x=0;char c=getchar(),flag='+';
while(!isdigit(c)) flag=c,c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
return flag=='-'?-x:x;
}
void init(int n)
{
np[1]=1;
for(int i=2;i<=n;i++)
{
if(!np[i]) p[++cnt]=i;
for(int j=1;j<=cnt&&i*p[j]<=n;j++)
{
np[i*p[j]]=1;
if(i%p[j]==0) break;
}
}
for(int i=1;i<=cnt;i++) sum[i]=(sum[i-1]+p[i])%mod;
}
ll S(ll x,int j)
{
if(x<=1||x<p[j]) return 0;
int t=(x<=B)?ind1[x]:ind2[n/x];
ll ans=g[t]-sum[j-1]-h[t]+(j-1);
if(j==1) ans+=2;
for(int k=j;k<=cnt&&p[k]*p[k]<=x;k++)
{
ll t1=p[k],t2=p[k]*p[k];
for(int e=1;t2<=x;e++,t1=t2,t2*=p[k])
ans=(ans+(p[k]^e)*S(x/t1,k+1)+(p[k]^(e+1)))%mod;
}
return ans;
}
int main()
{
cin>>n;
init(B=sqrt(n)+1);
for(ll l=1,r;l<=n;l=r+1)
{
r=n/(n/l);
val[++tot]=n/l;
if(n/l<=B) ind1[n/l]=tot;
else ind2[r]=tot;
ll t=(n/l)%mod;
h[tot]=(t-1)%mod;
g[tot]=(2+t)*(t-1)%mod*inv2%mod;
}
for(int j=1;j<=cnt;j++)
{
for(int i=1;i<=tot&&p[j]*p[j]<=val[i];i++)
{
int t=(val[i]/p[j]<=B)?ind1[val[i]/p[j]]:ind2[n/(val[i]/p[j])];
g[i]=(g[i]-p[j]*(g[t]-sum[j-1]))%mod;
h[i]=(h[i]-h[t]+j-1)%mod;
}
}
cout<<(S(n,1)%mod+1+mod)%mod;
return 0;
}
/*by DT_Kang*/