更多思路参考
洛谷日报是个好东西
more
①完全积性函数:
引入他们因为前缀和好求,第一个为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
#include
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_mapansmu,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