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);
    }
  • 相关阅读:
    最流行的javascript 代码规范
    jquery里阻止冒泡ev.stopPropagation()
    jquery里阻止冒泡ev.stopPropagation()
    响应式页面设计原理
    fromCharCode()的用法
    slice的用法
    java 反转数组
    java 一个数组的长度
    Java访问数组
    java 数组的定义
  • 原文地址:https://www.cnblogs.com/fht-litost/p/8711611.html
Copyright © 2011-2022 走看看