bzoj 4407 于神之怒加强版——反演

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4407

\( ans = \sum\limits_{D=1}^{min(n,m)}\frac{n}{D}*\frac{m}{D}\sum\limits_{d|D}d^{k}\mu (\frac{D}{d}) \)

设 \( g[ i ]=\sum\limits_{j|i}(\frac{i}{j})^{k}*\mu (j) \) ,则 g 是积性函数(因为 id 是积性函数,所以 idk 也是;u 也是积性,卷积起来也是积性),可以筛。

 g 在质因数幂地方的取值可以手动筛到一个质因数的时候赋了,遇到 i % pri[ j ] == 0 的时候就可以把 i 的 pri[ j ] 都拿出来,然后相乘得到了。

或者遇到 i % pri[ j ] == 0 的时候,发现这个 pri[ j ] 的贡献不在 \( \mu \) 里,所以只要给 g[ i ] 乘上 pri[ j ] 就行了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=5e6+5,mod=1e9+7;
int T,w,g[N],s[N],pri[N];bool vis[N];
void upd(int &x){x>=mod?x-=mod:0;}
int pw(int x,int k)
{int ret=1;while(k){if(k&1)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=1;}return ret;}
void init()
{
  int lm=5e6,cnt=0;
  g[1]=s[1]=1;
  for(int i=2;i<=lm;i++)
    {
      if(!vis[i])
    {
      pri[++cnt]=i;
      for(ll j=i,k=1;j<=lm;j*=i,k*=i)
        g[j]=pw(j,w)-pw(k,w)+mod,upd(g[j]),vis[j]=1;
    }
      for(int j=1;j<=cnt&&(ll)i*pri[j]<=lm;j++)
    {
      int d=i*pri[j]; if(vis[d])break; vis[d]=1;
      int k=d;while(k%pri[j]==0)k/=pri[j];
      g[d]=(ll)g[k]*g[d/k]%mod;
      if(i%pri[j]==0)break;
    }
      s[i]=s[i-1]+g[i];upd(s[i]);
    }
}
int main()
{
  scanf("%d%d",&T,&w); init(); int n,m;
  while(T--)
    {
      scanf("%d%d",&n,&m); if(n>m)swap(n,m);
      int ans=0;
      for(int i=1,j;i<=n;i=j+1)
    {
      int d0=n/i,d1=m/i; j=min(n/d0,m/d1);
      ans=(ans+(ll)d0*d1%mod*(s[j]-s[i-1]+mod))%mod;
    }
      printf("%d\n",ans);
    }
  return 0;
}

 

posted on 2018-12-13 09:23  Narh  阅读(95)  评论(0编辑  收藏  举报

导航