• HYSBZ


    self 同类分布

     HYSBZ - 1799 

    给出a,b,求出[a,b]中各位数字之和能整除原数的数的个数。Sample Input

    10 19

    Sample Output

    3

    Hint

    【约束条件】1 ≤ a ≤ b ≤ 10^18

    约束:一个数是它自己数位和的倍数,直接dp根本找不到状态,枚举数位和,因为总就162,然后问题就变成了一个数%mod=0,mod是枚举的,想想状态:dp[pos][sum][val],当前pos位上数位和是sum,val就是在算这个数%mod,(从高位算  *10+i),因为我们枚举的数要保证数位和等于mod,还要保证这个数是mod的倍数,很自然就能找到这些状态,显然对于每一个mod,val不能保证状态唯一,这是你要是想加一维dp[pos][sum][val][mod],记录每一个mod的状态(这里sum可以用减法,然而val不行,就只能加一维),那你就想太多了,这样是会超时的(因为状态太多,记忆化效果不好)。这里直接对每一个mod,memset一次就能ac。下面的代码还把limit的当做了状态,因为每次都要初始化,所以能这样,memset在多组外面是不能这样的,不过奇葩的,这代码,如果不把limit当状态,还是在!limit 条件下记录dp,提交一发,时间竟然更短了,可能是每次memset的关系!!!

                                                            ——引自wust_wenhao

    #include<cstdio>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=18+2,M=162+1;
    ll a[N],dp[N][M][M][2];
    ll dfs(int pos,int sum,int val,int mod,bool limit){
        if(sum-9*pos>0) return 0;
        //最坏的情况,这一位及后面的全部为9都不能达到0那就直接GG,这个剪枝不会影响ac
        if(!pos) return !sum && !val;
        if(dp[pos][sum][val][limit]!=-1) return dp[pos][sum][val][limit];
        int up=limit?a[pos]:9;
        ll ans=0;
        for(int i=0;i<=up;i++){
            if(sum-i<0) break;
            ans+=dfs(pos-1,sum-i,(val*10+i)%mod,mod,limit && i==a[pos]);
        }
        return dp[pos][sum][val][limit]=ans;
    }
    ll solve(ll x){
        int pos=0;ll ans=0;
        for(;x;x/=10) a[++pos]=x%10;
        for(int i=1;i<=pos*9;i++){//上限就是每一位都是9
            memset(dp,-1,sizeof dp);
            ans+=dfs(pos,i,0,i,true);
        }
        return ans;
    }
    int main(){
        for(ll a,b;~scanf("%lld%lld",&a,&b);){
            printf("%lld
    ",solve(b)-solve(a-1));
        }
        return 0;
    } 
  • 相关阅读:
    VS2010 正则批量替换头文件路径
    VC++ 内存泄露与检测的一种方法
    命令行编译C++程序
    Link1123:转换到COFF期间失败:文件无效或损坏
    C语言基础知识
    PCL深度图像(2)
    PCL关键点(1)
    PCL采样一致性算法
    PCL滤波介绍(3)
    PCL滤波介绍(2)
  • 原文地址:https://www.cnblogs.com/shenben/p/6411658.html
Copyright © 2020-2023  润新知