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;
    }
  • 相关阅读:
    jsp 特殊标签
    poj 1753 Flip Game 高斯消元 异或方程组 求最值
    zoj 3155 Street Lamp 高斯消元 异或方程组 求方案数
    poj1222 EXTENDED LIGHTS OUT 高斯消元解异或方程组 模板
    zoj 3930 Dice Notation 模拟
    zoj 3157 Weapon 线段树求逆序对数
    hdu 1242 Rescue BFS+优先队列
    hdu 3466 Proud Merchants 贪心+01背包
    zoj 3689 Digging 贪心+01背包
    hdu 2602 Bone Collector 01背包模板
  • 原文地址:https://www.cnblogs.com/Narh/p/9740786.html
Copyright © 2011-2022 走看看