zoukankan      html  css  js  c++  java
  • BZOJ 3679 数字之积

    3679: 数字之积

    Time Limit: 10 Sec  Memory Limit: 128 MB

    Description

    一个数x各个数位上的数之积记为f(x) <不含前导零>
    求[L,R)中满足0<f(x)<=n的数的个数

    Input

    第一行一个数n
    第二行两个数L、R

    Output

    一个数,即满足条件的数的个数

    Sample Input

    5
    19 22

    Sample Output

    1

    HINT

    100%     0<L<R<10^18 , n<=10^9

    分析 

    数位dp。真的是不会这种题啊,看着题解搞了一晚上。。。

    依照题意,可以设 dp[i][j]为i位的数的乘积为j的个数。由于n<=1e9,可以得出所有乘积数都是由2、3、5、7组成的,且每位数的乘积最多有几千种,因此我们可以预处理出乘积,并排序映射成dp[i][j]中的j。首先i位数一定是由i-1位数的状态乘上1-9得到的,按照这样的转移就能得到dp数组,然后对于区间[1,R)统计答案,首先将位数比R小的数都统计了,然后按位分解R,逐位处理(重点)。假如当前为的数为x3x2x1x0,把x3拿出来,计算位数为3的乘积为n/x3的数量,这样相当于x3这一位数字乘上任何位数为3的各位数的乘积都是小于等于n的。此后同理,具体看代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    long long f[10001];
    long long d[19][10001],s[19][10001];
    long long l,r,n;
    int tot=0;
    
    long long power(long long a,int t){
        long long temp;
        if (t==0) return 1;
        if (t==1) return a;
        temp=power(a,t/2);
        if (t%2==0) return temp*temp;
        else return temp*temp*a;
    }
    
    long long work(long long x,int n)
    {
        int i,ws=0,now;
        long long xx=x,ans=0;
        int a[20];
        while(xx){
            a[ws++]=xx%10;
            xx/=10;
        }
        for (i=1;i<ws;++i) ans += s[i][upper_bound(f+1,f+tot+1,n)-f-1];
    
        for(int i=ws;i>0;i--){
            for(int k=1;k<a[i-1];++k){
                if(n>=k){
                    if(i>1)
                        ans += s[i-1][upper_bound(f+1,f+tot+1,n/k)-f-1];
                    else ans++;
                }
            }
            if(a[i-1]) n/=a[i-1];
            else break;
        }
    
        return ans;
    }
    int main()
    {
        int i,j,k,p;
        long long z,ans;
        scanf("%lld%lld%lld",&n,&l,&r);
        for (i=0;i<=32;++i)
          for (j=0;j<=19;++j)
            for (k=0;k<=16;++k)
              for (p=0;p<=11;++p)
                {
                  z=power(2,i)*power(3,j)*power(5,k)*power(7,p);
                  if (z<=n&&z>0)
                    f[++tot]=z;
                }
        sort(f+1,f+tot+1);
        s[1][0]=0;
        for (i=1;i<=9;++i) d[1][i]=1;
        for (j=1;j<=tot;++j)
          s[1][j]=s[1][j-1]+d[1][j];
        for (i=2;i<=18;++i)
          {
            for (j=1;j<=upper_bound(f+1,f+tot+1,power(10,i))-f-1;++j)
              for (k=1;k<=9;++k)
                if (f[j]%k==0)
                  d[i][j]+=d[i-1][lower_bound(f+1,f+tot+1,f[j]/k)-f];
            s[i][0]=0;
            for (j=1;j<=tot;++j)
              s[i][j]=s[i][j-1]+d[i][j];
          }
        ans=work(r,n)-work(l,n);
        printf("%lld
    ",ans);
    }
  • 相关阅读:
    Azure PowerShell (2) 修改Azure订阅名称
    Windows Azure Platform Introduction (11) 了解Org ID、Windows Azure订阅、账户
    Azure PowerShell (3) 上传证书
    Azure PowerShell (1) PowerShell入门
    Windows Azure Service Bus (2) 队列(Queue)入门
    Windows Azure Service Bus (1) 基础
    Windows Azure Cloud Service (10) Role的生命周期
    Windows Azure Cloud Service (36) 在Azure Cloud Service配置SSL证书
    Android studio 使用心得(一)—android studio快速掌握快捷键
    android 签名、混淆打包
  • 原文地址:https://www.cnblogs.com/fht-litost/p/8711611.html
Copyright © 2011-2022 走看看