LOJ 572 「LibreOJ Round #11」Misaka Network 与求和——min_25筛

题目:https://loj.ac/problem/572

莫比乌斯反演得 \( ans=\sum\limits_{D=1}^{n}\left\lfloor\frac{n}{D}\right\rfloor^2\sum\limits_{d|D}f(d)^k\mu (\frac{D}{d}) \)

计算 \( S(n)=\sum\limits_{i=1}^{n}f×\mu \)

像杜教筛(https://blog.csdn.net/a1799342217/article/details/80328510)一样写一写式子,因为有 \( \mu \) 所以把补的 g 函数设为 1 函数。

  \( \sum\limits_{i=1}^{n}f×\mu×1(i) \)

 \( = \sum\limits_{i=1}^{n}\sum\limits_{d|D}1(d)*(f×\mu)(\frac{i}{d}) \)

 \( = \sum\limits_{d=1}^{n}1(d)\sum\limits_{i=1}^{\frac{n}{d}}f×\mu (i) \)

 \( = \sum\limits_{d=1}^{n}1(d)S(\frac{n}{d}) \)

用这个表示 \( S(n) \),则

  \( S(n)=\sum\limits_{d=1}^{n}1(d)S(\frac{n}{d}) - \sum\limits_{d=2}^{n}1(d)S(\frac{n}{d}) \)

  \( S(n)=\sum\limits_{i=1}^{n}f×\mu×1(i)- \sum\limits_{d=2}^{n}1(d)S(\frac{n}{d}) \)

  \( S(n)=\sum\limits_{i=1}^{n}f(i)- \sum\limits_{d=2}^{n}1(d)S(\frac{n}{d}) \)

用和 UOJ 188 一样的方法求 f 的前缀和即可。

 S 的可能角标一定是某个 \( \left\lfloor\frac{n}{i}\right\rfloor \) 。所以 S 可以预处理。预处理的时候别忘了记忆化。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define int unsigned int
#define ll long long
using namespace std;
int pw(int x,int k)
{int ret=1;while(k){if(k&1)ret*=x;x*=x;k>>=1;}return ret;}
const int N=9e4+5;
int n,k,base,s[N],g[N],w[N],m,p[N],pk[N],cnt,ans[N];
bool vis[N];ll p2[N];
int Id(int x){return x<=base?m-x+1:n/x;}
int S(int n)
{
  int k=Id(n);if(ans[k]!=-1)return ans[k];
  int ret=s[k]+g[k];
  for(int i=2,j;i<=n;i=n/j+1)
    {j=n/i;ret-=(n/j-i+1)*S(j);}
  return ans[k]=ret;
}
void init(int n)
{
  base=sqrt(n);
  for(int i=2;i<=base;i++)
    {
      if(!vis[i])p[++cnt]=i,p2[cnt]=(ll)i*i,pk[cnt]=pw(i,k);
      for(int j=1,d;j<=cnt&&(d=i*p[j])<=base;j++)
    {vis[d]=1;if(i%p[j]==0)break;}
    }
  for(int i=1,j;i<=n;i=n/j+1)w[++m]=j=n/i;

  for(int i=1;i<=m;i++)g[i]=w[i]-1;
  for(int j=1,tp=0;j<=cnt;j++,tp++)
    for(int i=1;i<=m&&p2[j]<=w[i];i++)
      g[i]-=g[Id(w[i]/p[j])]-tp;

  int p0=1;
  for(int j=cnt;j;j--)
    {
      while(p0<=m&&p2[j]<=w[p0])p0++;
      for(int i=p0-1;i;i--)
    {
      int k=Id(w[i]/p[j]);
      s[i]+=s[k]+pk[j]*(g[k]-(j-1));
    }
    }
  memset(ans,-1,sizeof ans);
  S(n);
}
signed main()
{
  scanf("%u%u",&n,&k);init(n);int prn=0;
  for(int i=1,j,lst=0,nw;i<=n;i=n/j+1)
    {
      j=n/i;nw=ans[Id(n/j)];
      prn+=j*j*(nw-lst);lst=nw;
    }
  printf("%u\n",prn);
  return 0;
}

 

posted on 2019-01-17 21:44  Narh  阅读(393)  评论(0编辑  收藏  举报

导航