• bzoj4652 [NOI2016]循环之美


    Description

    牛牛是一个热爱算法设计的高中生。在他设计的算法中,常常会使用带小数的数进行计算。牛牛认为,如果在 k 
    进制下,一个数的小数部分是纯循环的,那么它就是美的。现在,牛牛想知道:对于已知的十进制数 n 和 m,在 
    kk 进制下,有多少个数值上互不相等的纯循环小数,可以用分数 xy 表示,其中 1≤x≤n,1≤y≤m,且 x,y是整数
    。一个数是纯循环的,当且仅当其可以写成以下形式:a.c1˙c2c3…cp-1cp˙其中,a 是一个整数,p≥1;对于 1
    ≤i≤p,ci是 kk 进制下的一位数字。例如,在十进制下,0.45454545……=0.4˙5˙是纯循环的,它可以用 5/11
    、10/22 等分数表示;在十进制下,0.1666666……=0.16˙则不是纯循环的,它可以用 1/6 等分数表示。需要特
    别注意的是,我们认为一个整数是纯循环的,因为它的小数部分可以表示成 0 的循环或是 k?1 的循环;而一个小
    数部分非 0 的有限小数不是纯循环的。

    Input

    只有一行,包含三个十进制数N,M,K意义如题所述,保证 1≤n≤10^9,1≤m≤10^9,2≤k≤2000
     

    Output

    一行一个整数,表示满足条件的美的数的个数。
     

    Sample Input

    2 6 10

    Sample Output

    4
    explanation
    满足条件的数分别是:
    1/1=1.0000……
    1/3=0.3333……
    2/1=2.0000……
    2/3=0.6666……
    1/1 和 2/2 虽然都是纯循环小数,但因为它们相等,因此只计数一次;同样,1/3 和 2/6 也只计数一次。
     
     
     
    杜教筛板子题
    柿子还是比较好推
    这里补一个我一直没搞懂的证明
     
    求证:k进制下的纯循环小数的最简分数的分母一定与k互质
     
    设循环节长度为t,最简分数为a/b
    所以
     
    // luogu-judger-enable-o2
    //%std
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<set>
    #include<map>
    using namespace std;
    #define lovelive long long
    #define lc son[x][0]
    #define rc son[x][1]
    #define lowbit(x) (x&(-x))
    #define pt vc
    const lovelive mod=19260817;
    const int N=2e6+100;
    void read(lovelive &x)
    {
      lovelive p=1;
      x=0;
      char c=getchar();
      while(c<'0'||c>'9')
      {
        if(c=='-')
          p=-1;
        c=getchar();
      }
      while(c>='0'&&c<='9')
      { 
          x=x*10+c-48;
          c=getchar();
      } 
      x*=p;
    }
    struct hash_map{
      int ans[1000010],nxt[1000010],fir[mod+1],tot;
      lovelive hash[1000010];
      void add(lovelive x,int y)
      {
        int i=x%mod;
        nxt[++tot]=fir[i];
        fir[i]=tot;
        ans[tot]=y;
        hash[tot]=x;
      }
      int query(lovelive x)
      {
        for(int j=fir[x%mod];j;j=nxt[j])
          if(hash[j]==x)
            return ans[j];
        return -1;
      }
    }sp;
    int prime[N],miu[N],pre[N],tot;
    bool not_prime[N];
    void find_prime(int n)
    {
      miu[1]=1; 
      for(int i=2;i<=n;i++)
      {
        if(!not_prime[i])
          prime[++tot]=i,miu[i]=-1,pre[i]=i;
        for(int j=1;j<=tot&&prime[j]*i<=n;j++)
        {
          not_prime[i*prime[j]]=true;
          pre[i*prime[j]]=prime[j];
          if(i%prime[j]==0)
            break;
          miu[i*prime[j]]=-miu[i];
        }
      }
      for(int i=1;i<=n;i++)
        miu[i]+=miu[i-1]; 
    }
    lovelive calc(lovelive n)
    {
      if(n<=2e6)
        return miu[n];
      int tmp=sp.query(n*2000+1);
      if(tmp!=-1)
        return tmp;
      lovelive ans=1;
      for(lovelive i=2,r;i<=n;i=r+1)
      {
        r=n/(n/i);
        if(r>n)
          r=n;
        ans-=(r-i+1)*calc(n/i);
      }
      sp.add(n*2000+1,ans);
      return ans;
    }
    int a[20],cnt;
    lovelive f[2020];
    lovelive calc2(int n,int k)
    {
      return (n/k)*f[k]+f[n%k];
    }
    lovelive calc3(lovelive n,int k)
    {
      if(n<=1)
        return n;
      if(k==1)
        return calc(n);
      int tmp=sp.query(n*2000+k);
      if(tmp!=-1)
        return tmp;
      int p=pre[k];
      lovelive ans=calc3(n/p,k);
      tmp=k;
      while(tmp%p==0)
        tmp/=p;
      ans+=calc3(n,tmp);
      sp.add(n*2000+k,ans); 
      return ans;
    }
    int gcd(int x,int y)
    {
      if(!y)
        return x;
      return gcd(y,x%y);
    }
    int main()
    {
      lovelive n,m,k;
      read(n);read(m);read(k);
      for(int i=1;i<=k;i++)
        f[i]=(gcd(i,k)==1);
      for(int i=1;i<=k;i++)
        f[i]+=f[i-1];
      find_prime(2000000);
      a[0]=1;
      for(int j=1;prime[j]<=k;j++)
        if(k%prime[j]==0)
        {
          a[1<<cnt]=prime[j];
          ++cnt;
        }
      for(int j=1;j<(1<<cnt);j++)
        a[j]=a[j^lowbit(j)]*a[lowbit(j)];
      lovelive ans=0;
      for(lovelive i=1,r;i<=min(n,m);i=r+1)
      {
        r=min(n/(n/i),m/(m/i));
        if(r>min(n,m))
          r=min(n,m);
        ans+=(calc3(r,k)-calc3(i-1,k))*(n/i)*calc2(m/i,k);
      }
      cout<<ans<<"
    ";
      return 0;
    }
    /*
    1000000000 1000000000 960
    */ 
    View Code
  • 相关阅读:
    烂泥:KVM使用NAT联网并为VM配置iptables端口转发
    烂泥:CentOS6.5挂载windows共享文件夹
    烂泥:KVM、kickstart与FTP集成
    js-浅显基础-正则表达式集
    小程序-轮播图案例
    小程序-TabBar点击切换
    js-禁止微信内置浏览器调整字体大小
    小程序-分享到群或好友
    小程序-提交信息(姓名,电话)
    js-在url后面添加时间戳清除浏览器打开页面的缓存
  • 原文地址:https://www.cnblogs.com/NicoDafaGood/p/8985706.html
Copyright © 2020-2023  润新知