zoukankan      html  css  js  c++  java
  • bzoj 3309 DZY Loves Math——反演+线性筛

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

    像这种数据范围,一般是线性预处理,每个询问 sqrt (数论分块)做。

    先反演一番。然后 f( ) 还不能一个就花 log 的时间,所以要分析性质。

    设 n 一共 m 个质因数,其中最大的指数是 t 。

    已有 Σ(d|n) f(d)*u(n/d) ,如果 u( ) 的部分含有指数>=2的质因子,就无贡献;所以 u( ) 里每种质因数选1个或0个,一共 2^m 种。

    如果 n 里有一个质因子的指数<t ,则卷积的值是0。因为 u 含有的所有集合可以分成含该因子、不含该因子两部分。这两部分含有的集合个数相同,u的符号正好相反,值相同(因为该质因子的有无不影响 f( ) 的值,因为 f( ) 的值是 t 或 t-1),所以求和为0。

    所以 n 的质因子必须齐次。那么只有 u( ) 含有所有质因子的时候,f( ) 的值才是 t-1 ,否则都是 t 。除了这两项,其余消成0;再考虑 u( ) 的符号,于是 Σ(d|n) f(d)*u(n/d) = (-1)^(m+1)。

    设 g(n) = Σ(d|n) f(d)*u(n/d) ,则 g( ) 可以线性筛。只要记录每个数是否齐次、如果齐次的话次数是几、一共多少种质因子,就能筛了。然后每个询问数论分块即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int N=1e7+5;
    int T,n,m,g[N],pri[N],cnt,c[N],v[N];
    ll ans;
    bool fx[N],vis[N];
    int rdn()
    {
      int ret=0;bool fx=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
      while(ch>='0'&&ch<='9') ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
      return fx?ret:-ret;
    }
    void calc(int a,int b,int &x,int &y)
    {
      x=0; y=0;
      while(a%b==0)y++,a/=b;
      x=a;
    }
    void init()
    {
      int lm=1e7;
      for(int i=2;i<=lm;i++)
        {
          if(!vis[i])pri[++cnt]=i,g[i]=g[i-1]+1,fx[i]=c[i]=v[i]=1;
          else g[i]=g[i-1]+(fx[i]?(v[i]&1?1:-1):0);
          
          for(int j=1,k;j<=cnt&&((ll)i*pri[j]<=lm);j++)
        {
          vis[k=i*pri[j]]=1;
          if(i%pri[j]==0)
            {
              int d,a;calc(i,pri[j],d,a);
              if(d==1)
            fx[k]=1,c[k]=a+1,v[k]=1;
              else if(fx[d]&&c[d]==a+1)
            fx[k]=1,c[k]=c[d],v[k]=v[d]+1;
              break;
            }
          else if(fx[i]&&c[i]==1)
            fx[k]=1,c[k]=1,v[k]=v[i]+1;
        }
        }
    }
    int main()
    {
      init();
      T=rdn();
      while(T--)
        {
          n=rdn(); m=rdn(); int nt1,nt2;
          if(n>m) swap(n,m);
          for(int i=1;i<=n;i=min(nt1,nt2)+1)
        {
          nt1=(n/i); nt2=(m/i);
          ll d=(ll)nt1*nt2*(g[min(nt1=n/nt1,nt2=m/nt2)]-g[i-1]);
          ans+=d;
        }
          printf("%lld
    ",ans); ans=0;
        }
      return 0;
    }
  • 相关阅读:
    [leetcode]Valid Number
    [leetcode]Edit Distance
    [leetcode]Decode Ways
    [leetcode]Maximum Depth of Binary Tree
    [topcoder]BadNeighbors
    [topcoder]ZigZag
    [leetcode]Subsets II
    [leetcode]Merge Sorted Array
    [leetcode]Binary Tree Maximum Path Sum
    hdu 2964 Prime Bases(简单数学题)
  • 原文地址:https://www.cnblogs.com/Narh/p/9740786.html
Copyright © 2011-2022 走看看