Codeforces 628D 数位dp

题意:d magic number(0<=d<9)的意思就是一个数,从最高位开始奇数位不是d,偶数位是d

题目问,给a,b,m,d(a<=b,m<2000)问,a,b之间有多少个数满足既是d magic number,又可以被m整除

a,b的范围很大,都是2000位,且a,b的位数一样,这一点很重要

分析:这题一看又有取模,又是大整数,那肯定是要用数位dp做,

通常的数位dp,我们要解决(0,x)的区间中的答案,但是这个题不需要,

注意刚才我说过一点,a,b是位数相同的整数,假设solve()函数能解决x到和它同位的最小整数的区间范围内的答案

那么最终答案,就是solve(b)-solve(a)+is(a),

这样我们的工作就简单了,不需要统计位数比它小的数

我们从高位开始进行dp

下面定义状态

1: dp[i][j][1],代表现在处理到第 i 位 且前缀 i 位形成的整数n%m=j 的 方案数,且现在形成的整数等于上限

2: dp[i][j][0],代表现在处理到第 i 位 且前缀 i 位形成的整数n%m=j 的 方案数,且现在形成的整数小于上限

那么状态转移方程就很好想了

设字符串长度为n  那么时间复杂度是O(nm)的

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 2e3+5;
const int mod = 1e9+7;
int dp[N][N][2],num[N],m,d;
char a[N],b[N];
int solve(char *s)
{
    int l=strlen(s+1);
    memset(dp,0,sizeof(dp));
    for(int i=1; i<=l; ++i)
        num[i]=s[i]-‘0‘;
    for(int i=1; i<=9; ++i)
    {
        if(i==d)continue;
        if(i<num[1])++dp[1][i%m][0];
        else if(i==num[1])++dp[1][i%m][1];
    }
    for(int i=2; i<=l; ++i)
    {
        if(i%2==0)
        {
            for(int j=0; j<m; ++j)
            {
                int cur=(j*10+d)%m;
                dp[i][cur][0]=(dp[i][cur][0]+dp[i-1][j][0])%mod;
                if(d<num[i])
                    dp[i][cur][0]=(dp[i][cur][0]+dp[i-1][j][1])%mod;
                else if(num[i]==d)
                    dp[i][cur][1]=(dp[i][cur][1]+dp[i-1][j][1])%mod;
            }
        }
        else
        {
            for(int k=0; k<10; ++k)
            {
                if(k==d)continue;
                for(int j=0; j<m; ++j)
                {
                    int cur=(j*10+k)%m;
                    dp[i][cur][0]=(dp[i][cur][0]+dp[i-1][j][0])%mod;
                    if(k<num[i])
                        dp[i][cur][0]=(dp[i][cur][0]+dp[i-1][j][1])%mod;
                    else if(k==num[i])
                        dp[i][cur][1]=(dp[i][cur][1]+dp[i-1][j][1])%mod;
                }
            }
        }
    }
    return (dp[l][0][0]+dp[l][0][1])%mod;
}
int judge(char *s)
{
    int l=strlen(s+1),sum=0;
    for(int i=1;i<=l;++i)
    {
        int x=s[i]-‘0‘;
        if(i%2&&x==d)return 0;
        if(!(i%2)&&x!=d)return 0;
        sum=(sum*10+x)%m;
    }
    if(!sum)return 1;
    return 0;
}
int main()
{
    scanf("%d%d%s%s",&m,&d,a+1,b+1);
    int ans=(solve(b)-solve(a)+judge(a)+mod)%mod;
    printf("%d\n",ans);
    return 0;
}

时间: 2024-10-10 10:57:44

Codeforces 628D 数位dp的相关文章

Codeforces 55D (数位DP+离散化+数论)

题目链接: http://poj.org/problem?id=2117 题目大意:统计一个范围内数的个数,要求该数能被各位上的数整除.范围2^64. 解题思路: 一开始SB地开了10维数组记录情况. 首先要求能被各位上的数整除,可以转化为被一个数整除问题. 这个数就是各位上数的最小公倍数LCM(不是GCD). 其次,处理整除问题,得转化成数位DP的余数模板.1~9的LCM最大是2520, 那么%2520,让其可以开数组进行记忆化搜索. 最后, 对于不能%2520最后结果,再%各个数位累计过来的

codeforces 215E 数位DP

题意:一个数的二进制表示如果是一个周期数那么它就是需要的,问[l,r]中有多少个好的数 题解:明显很像数位DP,枚举第一周期的长度,根据第一周期的数值大小来确定有多少种方案,注意首位不能为0.然后就是要注意去重问题,因为对于第一周期长度为k算到的数字,长度为k可以整除的数时必定也算过一遍,减一下就好了,根据这个去重 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<stri

Find a car CodeForces - 809C (数位DP)

大意: 给定一个$1e9\times 1e9$的矩阵$a$, $a_{i,j}$为它正上方和正左方未出现过的最小数, 每个询问求一个矩形内的和. 可以发现$a_{i,j}=(i-1)\oplus (j-1)+1$, 暴力数位$dp$即可 #include <iostream> #include <sstream> #include <algorithm> #include <cstdio> #include <cmath> #include &l

codeforces Hill Number 数位dp

http://www.codeforces.com/gym/100827/attachments Hill Number Time Limits:  5000 MS   Memory Limits:  200000 KB 64-bit interger IO format:  %lld   Java class name:  Main Description A Hill Number is a number whose digits possibly rise and then possibl

[Codeforces 258B &amp; 259 D]Little Elephant and Elections 数位dp+dfs

http://codeforces.com/problemset/problem/258/B 题目大意: 说七个party选择数字(各不相同) 而规定的小象的party选择的数字之中所拥有的数字4和7的个数要比其他六个party拥有的个数之和还要严格多,询问方案数. 如m=7时其余的随意选择至少会拥有一个4或7,与题意矛盾,故方案数为0 m=8时,7 1 2 3 5 6 8是一种合法方案 思路: 由于小象的party选到的数字所含4和7的个数至多和m的位数一样多,则枚举小象的party所含4和7

CodeForces 258B Little Elephant and Elections 数位DP

前面先用数位DP预处理,然后暴力计算组合方式即可. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include

CodeForces 55D Beautiful numbers(数位dp+数学)

题目链接:http://codeforces.com/problemset/problem/55/D 题意:一个美丽数就是可以被它的每一位的数字整除的数. 给定一个区间,求美丽数的个数. 显然这是一道数位dp,就是满足一个数能被所有位数的lcm整除即可. 一般都会设dp[len][mod][LCM],mod表示余数,LCM表示前len位的lcm. 但是如果直接裸mod会很复杂,于是再想lcm{0,1,2,3,4,5,6,7,8,9}=2520; 而且lcm{a,b,c,d....}{a,b,c,

数位dp专题 (HDU 4352 3652 3709 4507 CodeForces 55D POJ 3252)

数位dp核心在于状态描述,因为阶段很简单. 一般都是求有多少个数,当然也有求平方的变态题. 因为比这个数小的范围定然是从左至右开始小的,那么什么样的前缀对后面子数有相同的结果? HDU 3652 题意:求能被13整除且含有13这样数的个数. 赤裸裸的两个条件,加上个pre标明下前缀,其实直接开状态也是一样的.整除这个条件可以用余数来表示.余数转移:(mod*10+i)%13 /* *********************************************** Author :bi

CodeForces 55D Beautiful numbers 数位DP+数学

题意大概是,判断一个正整数区间内有多少个整数能被它自身的每一个非零的数字整除. 因为每一个位置上的整数集s = {0,1,2,3,4,5,6,7,8,9} lcm(s) = 2520 现在有一个整数t是由s中一个或者多个数字构成的,记为abcde,显然t = a*10^4+b*10^3+c*10^2+d*10^1+e 要使得t能被a,b,c,d,e整除,必然有t % lcm(a,b,c,d,e) = 0 因为a,b,c,d,e去重之后一定是s的一个子集,所以lcm(s)一定是lcm(a,b,c,