zoukankan      html  css  js  c++  java
  • BZOJ1799 [Ahoi2009]self 同类分布

    BZOJ1799 [Ahoi2009]self 同类分布

    Description

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

    Sample Input

    10 19

    Sample Output

    3

    HINT

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


    题解Here!

    本蒟蒻表示不会数位$DP$,药丸。。。

    首先把询问拆成$sum(b)-sum(a-1)$应该都会。

    然后本蒟蒻就不会了。。。

    本题记录前面的数字的和,同时还要知道最后产生的数字是否整除和。

    记录各位数字的和比较容易,共$9 imes 18$个状态。

    关键是如何知道已经产生 的数位构成的数字是否整除最后的总和,比较麻烦。

    考虑求模,整除的模数为$0$,可以记录已经产生的数字的模数,但是又不知道最后的数字总和是多少,这个模数怎么记录?

    可以这样定义:

    $dp[i][sum][m][mod]$表示到第i位,前面数字总和为$sum$ ,$mod mod$的值为$m$,然后枚举$mod$即可计算。

    这样可以解决问题,但是计算内存发现:$dp[20][200][200][200]$需要1G的内存,只好想办法压 缩空间,因为$mod$是要在程序中枚举的,所以不必记录这一维状态,这样空间就足够了。

    $dp[i][sum][m][0/1]$表示到第$i$位,前面数字总和为$sum$,$mod mod$的值为$m$,0表示没卡上界,1表示卡了上界,然后枚举$mod$即可计算

    写数位dp的时候,我习惯考虑从当前状态进行拓展,也就是所谓的刷表大法。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #define MAXN 210
    #define MAXM 30
    using namespace std;
    int top,bit[MAXM];
    long long a,b,dp[MAXM][MAXN][MAXN][2];
    inline long long read(){
        long long date=0,w=1;char c=0;
        while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
        while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
        return date*w;
    }
    long long solve(long long x){
        long long ans=0;
        top=0;
        while(x){bit[++top]=x%10;x/=10;}
        reverse(bit+1,bit+top+1);
        for(int sum=1;sum<=top*9;sum++){
            memset(dp,0,sizeof(dp));
            dp[0][0][0][1]=1;
            for(int i=0;i<top;i++)
            for(int j=0;j<=sum;j++)
            for(int k=0;k<=sum;k++)
            for(int c=0;c<=1;c++){
                if(!dp[i][j][k][c])continue;
                for(int l=0;l<=(c?bit[i+1]:9);l++){
                    if(j+l>sum)break;
                    dp[i+1][j+l][(k*10+l)%sum][c&(l==bit[i+1])]+=dp[i][j][k][c];
                }
            }
            ans+=dp[top][sum][0][0]+dp[top][sum][0][1];
        }
        return ans;
    }
    int main(){
        a=read();b=read();
        printf("%lld
    ",solve(b)-solve(a-1));
        return 0;
    }
    
  • 相关阅读:
    Java网络编程详解
    android 取mac若干问题
    android问题 This version of android studio is incompatible with the gradle version used.
    c#将DataTable内容导出为CSV文件
    C#下利用正则表达式实现字符串搜索功能的方法(转)
    C#正则表达式入门
    java 文件类 null与exists()是不一样的
    c#线程中下载文件到本地
    Git 常用命令
    Web 监听器
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9426533.html
Copyright © 2011-2022 走看看