BZOJ 2820: YY的GCD [莫比乌斯反演]

题解:

和上一题相同的函数:

  为满足的对数

  为满足的对数

显然,反演后得到

 

可以枚举每一个质数,套用上一题的做法,p相当于k,d*p也就是p的倍数了...很像上一题我WT1中的式子

 

其实d只要枚举到min(n,m)/p

然而复杂度承受不了,大约n/logn*sqrt(n)

我们设,那么继续得到

注意:之前有人跟我说ll和int速度差不多。。事实并不如此

所以能不用ll的地方还是不要用 避免被卡常

#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int n,m;
#define INF 3e8
const int maxn=1e7+100;
const int N=1e6+100;
int miu[maxn],sum[maxn],prime[N],pnum,ans,T;
int main()
{
    freopen("noip.in","r",stdin);
    freopen("noip.out","w",stdout);
    cin>>T;
    miu[1]=1;
    for (int i=2;i<maxn;i++) miu[i]=-INF;
    for (int i=2;i<maxn;i++)
    {
      if (miu[i]==-INF)
      {
        miu[i]=-1;
        prime[++pnum]=i;
      }
      for (int j=1;j<=pnum;j++)
      {
        if (i*prime[j]>=maxn) break;
        if (i%prime[j]==0) miu[i*prime[j]]=0;
        else miu[i*prime[j]]=-miu[i];
      }
    }
    for (int i=1;i<=pnum;i++)
      for (int j=1;j<=(maxn-10)/prime[i];j++)
        sum[j*prime[i]]+=miu[j];
    for (int i=1;i<=maxn-10;i++) sum[i]+=sum[i-1];
    while (T--)
    {
        cin>>n>>m;
        if (n>m) swap(n,m);
        ll ans=0;int j;
        for (int i=1;i<=n;i=j+1)
        {
            j=min(n/(n/i),m/(m/i));
            ans+=1ll*(n/i)*(m/i)*(sum[j]-sum[i-1]);
        }
        cout<<ans<<endl;
    }
    return 0;
}

 

#updata 18.11

#include <bits/stdc++.h>
using namespace std;
#define rint register ll
#define IL inline
#define rep(i,h,t) for (ll i=h;i<=t;i++)
#define dep(i,t,h) for (ll i=t;i>=h;i--) 
#define ll long long
const ll N=1e7+1;
const ll M=N+1e4;
ll mu[M],cnt,p[M];
ll ans[N];
bool pd[M];
int main()
{
  ios::sync_with_stdio(false);
  ll T;
  cin>>T;
  pd[1]=1; mu[1]=1;
  rep(i,2,N)
  {
    if (!pd[i]) p[++cnt]=i,mu[i]=-1;
    for (ll j=1;j<=cnt&&p[j]*i<=N;j++)
    {
      pd[p[j]*i]=1;
      if (i%p[j]==0) break;
      else mu[i*p[j]]=-mu[i];
    }
  }
  rep(i,2,N)
    if (!pd[i])
      for (ll j=1;i*j<=N;j++)
        ans[i*j]+=mu[j];
  rep(i,1,N) ans[i]+=ans[i-1];
  rep(ttt,1,T)
  {
    ll n,m;
    cin>>n>>m;
    ll i=1;
    ll ans2=0;
    while (i<=n&&i<=m)
    {
      ll x1=n/(n/i),x2=m/(m/i); 
      if (x1<=x2)
      {
        ans2+=(n/i)*(m/i)*(ans[x1]-ans[i-1]);
        i=x1+1;
      } else
      {
        ans2+=(n/i)*(m/i)*(ans[x2]-ans[i-1]);
        i=x2+1;
      }
    }
    cout<<ans2<<endl;
  }
  return 0;
}

 

posted @ 2018-11-13 09:33  尹吴潇  阅读(160)  评论(0编辑  收藏  举报