積性函式字首和問題
阿新 • • 發佈:2018-11-25
1. 求前n個正整數的約數之和
即 .
解:
或
需要說明的是 是一種常見的表示形式。
當 時, 顯然只有個取值,當 時, ,顯然也只有個取值。當 = k (常數) 時,i的取值區間是 ,因此可以用 複雜度求解。
code:
#include <cstdio> #include <algorithm> #include <cstring> using namespace std; typedef long long ll; ll n,i,a,b; ll sum; int main(){ scanf("%lld",&n); sum = 0; for(i=1;i*i<=n;i++){ sum += i * (n / i); b = n/i; a = n/(i+1)+1; sum += (a+b) * (b-a+1) / 2 * i; } i--; if (i*i == n) sum -= i * (n / i); printf("%lld\n",sum); return 0; }
2.求
設, .
所以,兩個函式的狄利克雷卷積 .
(杜教篩求解)
其中:, .
code:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int MAX = 1e7; const ll MOD = 1000000007; ll n,p; ll phi[MAX+10],prime[MAX+10]; bool check[MAX+10]; inline ll read() { register ll x=0,t=1;register char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } ll extendGcd(ll a, ll b, ll &x, ll &y) { ll ans, t; if (b == 0) { x = 1; y = 0; return a; } ans = extendGcd(b, a%b, x, y); t = x; x = y; y = t - (a / b)*y; return ans; } ll inv(ll a, ll m) { ll x, y, d; d = extendGcd(a, m, x, y); if (d == 1) return (x%m + m) % m; else return -1; } void get_sum() { memset(check,false,sizeof(check)); phi[1]=1; int tot=0; for(int i=2;i<=MAX;i++){ if(!check[i]){ prime[tot++]=i; phi[i]=i-1; } for(int j=0;j<tot&&i*prime[j]<=MAX;j++){ check[i*prime[j]]=true; if(i%prime[j]==0){ phi[i*prime[j]]=phi[i]*prime[j]; break; } else{ phi[i*prime[j]]=phi[i]*phi[prime[j]]; } } } for(ll i=2;i<=MAX;i++) phi[i]=(phi[i-1]+phi[i]*(i*i%p))%p; } map<ll,ll>dp; ll inv2; ll inv6; ll get(ll x,ll y) { x=(x-1)%p; y%=p; ll tmp1=y*(y+1)%p*(2*y+1)%p*inv6%p; ll tmp2=x*(x+1)%p*(2*x+1)%p*inv6%p; ll ans=(tmp1-tmp2+p)%p; return ans; } ll gett(ll x) { x%=p; ll ans=x*(x+1)%p*inv2%p; ans=ans*ans%p; return ans; } //所求字首和 ll cal(ll x) { if(x<=MAX) return phi[x]; if(dp[x]) return dp[x]; ll pos; ll tmp=0; for(ll i=2;i<=x;i=pos+1){ pos=x/(x/i); tmp+=get(i,pos)*cal(x/i)%p; tmp%=p; } dp[x]=gett(x)-tmp; return dp[x]; } //洛谷3768 int main() { p=read(); n=read(); inv2=inv(2,p); inv6=inv(6,p); get_sum(); ll pos; ll ans=0; for(ll i=1;i<=n;i=pos+1){ pos=n/(n/i); ans=(ans+gett(n/i)*((cal(pos)-cal(i-1)+p)%p)%p)%p; } printf("%lld\n",ans); return 0; }