一.狄利克雷卷积
①完全积性函数:
引入他们因为前缀和好求,第一个为1,第二个为n,第三个为
不完全积性函数:
②公式:
f一般为待求的,比如
g一般根据③中三个关系,自己构造的,比如
③常用关系:
a.
b.
c.(有上面两个式子得)
④例子:见下
二.杜教筛
一般n达到1e9以上,线性筛TLE,就得上这个玩意了,可以非线性时间解决。
①构造思路
核心式子:S为f的前缀和
(证明见链接)
注意证明第二步到第三步实际上是提出gd,然后用i替换i/d, 和式性质链接
a. ,由于,我们设,这样 单位元,取到1值为1,其他情况值为0,所以和就是1
b.,由于,我们设 , 这样 id取到1~n,所以和为n(n+1)/2
②模板&代码细节 BZOJ 3944 or P4213
先线性筛预处理一部分,然后剩下比较大的数没处理,用杜教筛(S_phi和S_mu部分),这时要递归+map找
#include <bits/stdc++.h>
#include<tr1/unordered_map>
using namespace std;
using namespace std::tr1;//头文件和std都要加,c++11可用
typedef long long ll;
typedef unsigned long long ull;
const int N = 5e6;
const int maxn=2147483647;//为了过此题,强设第二个上界
ll mu[N+20],phi[N+20];
int prime[N+20];
int vis[N+20];
unordered_map<int,ll>ansmu,ansphi;//数组不够大,额外开,需要map
//unorder_map比普通map少了排序,会快一些
inline int read() { //输入挂
int X=0,w=1; char c=getchar();
while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
return X*w;
}
void init()
{
int cnt=0;
phi[1]=mu[1]=1;
for(int i=2;i<=N;i++)//统一ll和int!!!
{
if(!vis[i])
{
prime[++cnt]=i;//++写在前面
phi[i]=i-1;//素数 p欧拉函数=p-1
mu[i]=-1;//素数 只有它本身一个素因子
}
for(int j=1;prime[j]*i<=N&&j<=cnt;j++)//不越两界
{
vis[i*prime[j]]=1;
if(i%prime[j]==0)
{
//mu[i*prime[j]]=0;//初始化为0所以这项可有可无
phi[i*prime[j]] =phi[i]*prime[j];//性质
break;
}
else
{
phi[i*prime[j]]=phi[i]*(prime[j]-1);//积性函数性质
mu[i*prime[j]]=-mu[i];//多一个素因子变正负
}
}
}
for(int i=1;i<=N;i++)mu[i]+=mu[i-1],phi[i]+=phi[i-1];//前缀和
}
ll S_phi(ll n)//分块和找超出预处理范围的数
{
if(n<=N)return phi[n];//已经预处理过的
if(ansphi[n])return ansphi[n];//已经递归找到的
ll ans=0;
for(ll l=2,r;r<maxn&&l<=n;l=r+1) //分块
r=n/(n/l) ,ans+=(r-l+1)*S_phi(n/l); //I*phi,I和就是区间长度
return ansphi[n]=(ull)n*(n+1ll)/2ll-ans; //这题特殊,要转ull防溢出
}
ll S_mu(ll n)
{
if(n<=N)return mu[n];//同上
if(ansmu[n])return ansmu[n];
ll ans=0;
for(ll l=2,r;r<maxn&&l<=n;l=r+1) //这里ll不然莫名超时
r=n/(n/l) ,ans+=(r-l+1)*S_mu(n/l); //I*mu
return ansmu[n]=1ll-ans;
}
int main()
{
init();
int T=read();
while(T--)
{
int n=read();
printf("%lld %lld\n",S_phi(n),S_mu(n));
}
return 0;
}