Description
题解
强行拼题来着啊2333
推一发柿子可以得到一个线性的做法就是
a n s = ∑ i = 1 n f ( i ) ∗ ( ∑ j = 1 n i ϕ ( j ) ∗ 2 − 1 ) ans=\sum_{i=1}^{n}f(i)*(\sum_{j=1}^{\frac{n}{i}}\phi(j)*2-1) ans=i=1∑nf(i)∗(j=1∑inϕ(j)∗2−1)
然后就不会了啊qwq
如果设 s u m ( x ) = ∑ i = 1 x ϕ ( i ) sum(x)=\sum_{i=1}^{x}\phi(i) sum(x)=∑i=1xϕ(i),那么其实后面那项就是
( s u m ( ⌊ n i ⌋ ) ∗ 2 − 1 ) (sum(\lfloor\frac{n}{i}\rfloor)*2-1) (sum(⌊in⌋)∗2−1)
那么如果能快速算出 f ( x ) f(x) f(x)的前缀和,我们就可以对后面数论分块套个杜教筛玩了qwq
这个东西是可以用类似min-25筛的东西做出来的
我们考虑一个数 x x x,他要不就是质数,要不他至少有一个因子是小于 N \sqrt N N的,且最大质因数不小于 N \sqrt N N
所以我们考虑在 N \sqrt N N的上界从大往小枚举开筛
不妨设 S ( n , m ) S(n,m) S(n,m)表示对于一类上界为 n n n的数,次小质因子至少在 m m m以上的数的 f f f和
转移如下
S ( n , m ) = ∑ j > = m p r [ j ] 2 < = n ∑ k = 1 p r [ j ] k + 1 < = n S ( n p r [ j ] k , j + 1 ) + p r [ j ] k ∑ i = p r [ j ] n p r [ j ] k [ i is a prime ] S(n,m)=\sum_{j>=m}^{pr[j]^2<=n}\sum_{k=1}^{pr[j]^{k+1}<=n}S(\frac{n}{pr[j]^k},j+1)+pr[j]^k\sum_{i=pr[j]}^{\frac{n}{pr[j]^k}}[\text{i is a prime}] S(n,m)=j>=m∑pr[j]2<=nk=1∑pr[j]k+1<=nS(pr[j]kn,j+1)+pr[j]ki=pr[j]∑pr[j]kn[i is a prime]
解释一下
对于前面一个 S S S的转移,我们理解为他并非次大质因数,故我们枚举他的次幂转移
对于后面一个转移,相当于他是次大质因数,此时一定有一个比他大的质数作为最大质因子,所以后面一段实际上是一个质数个数和,用min-25筛简单预处理即可
似乎还是可以做次小质因子的贡献的23333
以后出来毒一下qwq
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#include<unordered_map>
#define LL long long
#define ui unsigned int
#define mp(x,y) make_pair(x,y)
#define pui pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int stack[20];
inline void write(ui x)
{
if(x<0){putchar('-');x=-x;}
if(!x){putchar('0');return;}
int top=0;
while(x)stack[++top]=x%10,x/=10;
while(top)putchar(stack[top--]+'0');
}
inline void pr1(ui x){write(x);putchar(' ');}
inline void pr2(ui x){write(x);putchar('\n');}
const int MAXN=2000005;
const int MAXM=90005;
int pr[MAXN],pre[MAXN],plen,K;
bool is[MAXN];
ui phi[MAXN],pw[MAXN];
ui pow_mod(ui a,int b)
{
ui ret=1;
while(b)
{
if(b&1)ret=ret*a;
a=a*a;b>>=1;
}
return ret;
}
void init()
{
phi[1]=1;
for(int i=2;i<MAXN;i++)
{
if(!is[i])pr[++plen]=i,phi[i]=i-1,pw[plen]=pow_mod(i,K);
for(int j=1;j<=plen&&i*pr[j]<MAXN;j++)
{
is[i*pr[j]]=true;
if(!(i%pr[j])){phi[i*pr[j]]=phi[i]*pr[j];break;}
phi[i*pr[j]]=phi[i]*(pr[j]-1);
}
}
for(int i=2;i<MAXN;i++)phi[i]+=phi[i-1],pre[i]=pre[i-1]+(!is[i]);
}
ui id[MAXN],n,N;
int getid(int x){return x<=N?x:n/x+N;}
ui solvephi(int x)
{
if(x<MAXN)return phi[x];
int u=getid(x);
if(id[u]!=-1)return id[u];
ui ret=1LL*(x+1)*x/2;
for(int i=2,nxt;i<=x;i=nxt+1)
{
nxt=x/(x/i);
ret-=(nxt-i+1)*solvephi(x/i);
}
return id[u]=ret;
}
int id1[MAXM],g[MAXM],ps[MAXM],NN;
int getid1(int x,int li){return x<=NN?x:li/x+NN;}
int getpr(int n)//质数个数和
{
if(n<=1)return 0;
int m=0;NN=sqrt(n);
for(int i=1,nxt;i<=n;i=nxt+1)
{
nxt=n/(n/i);int u=n/i;
if(u<=NN)id1[u]=++m;else id1[n/u+NN]=++m;
g[m]=u-1;ps[m]=u;
}
for(int j=1;pr[j]<=NN;j++)
for(int i=1;i<=m;i++)
{
if(pr[j]*pr[j]>ps[i])break;
g[i]-=(g[id1[getid1(ps[i]/pr[j],n)]]-pre[pr[j-1]]);
}
return g[1];
}
unordered_map<int,ui> mp[MAXM];
ui sum[MAXN];
ui S(int n,int m)
{
if(n<2||pr[m]>n)return 0;
if(mp[m][n])return mp[m][n];
ui ret=0;
for(int j=m;j<=plen&&1LL*pr[j]*pr[j]<=n;j++)
{
int lin=pr[j];
for(int k=1;1LL*lin*pr[j]<=n;k++)
{
ret+=S(n/lin,j+1);
ret+=pw[j]*(sum[getid(n/lin)]-j+1);
lin*=pr[j];
}
}
return mp[m][n]=ret;
}
ui ph[MAXN],us[MAXN];
int main()
{
memset(id,-1,sizeof(id));
n=read();K=read();N=sqrt(n);
init();
getpr(n);
for(int i=1,nxt;i<=n;i=nxt+1)
{
nxt=n/(n/i);int u=n/i;
sum[getid(u)]=g[id1[getid1(u,n)]];
ph[getid(u)]=solvephi(u);
}
ui ans=0;ui lst=0;
for(int i=1,nxt;i<=n;i=nxt+1)
{
nxt=n/(n/i);int u=n/i;
ui num=S(nxt,1)+g[id1[getid1(nxt,n)]];
ui s1=ph[getid(u)]*2-1;
ui s2=num-lst;
lst=num;
ans+=s1*s2;
}
pr2(ans);
return 0;
}