cf 55D 数位dp 好题

/*
刚开始我考虑0的情况,想将他剔除就将lcmn设为-1,这样还要判断0和lcmn是-1的情况很麻烦而且但是一直出错
后来觉得不用管0的情况就行了,可以认为符合。
解:将lcmn离散化,因为1-9的公倍数必是2520的因子并且只有48个
所以用一个数组离散化,记忆的时候直接调用离散数组即可
因为一个数的所有数字的最小公倍数必定是2520的因子,所以将这个数对2520取余缩小范围并记忆
三维,第一个长度,第二个对2520取余,第三个是lcm值
*/
#include<stdio.h>
#include<string.h>
#define ll  __int64
ll dp[20][2600][50];
ll fp[2600];
ll digit[20];
ll gcd(ll a,ll b) {
if(b==0)return a;
return gcd(b,a%b);
}
ll dfs(ll len,ll mod,ll lcmn,ll ok) {
    if(!len) return mod%lcmn==0;
    if(!ok&&dp[len][mod][fp[lcmn]]!=-1)
        return dp[len][mod][fp[lcmn]];
    ll i,ans=0,maxx=ok?digit[len]:9;
    for(i=0;i<=maxx;i++) {
     if(i==0)
        ans+=dfs(len-1,(mod*10+i)%2520,lcmn,ok&&i==maxx);//如果是0的话就跳过
    else
        ans+=dfs(len-1,(mod*10+i)%2520,lcmn*i/gcd(lcmn,i),ok&&i==maxx);//求lcmn和和
    }
    if(!ok)
        dp[len][mod][fp[lcmn]]=ans;
    return ans;
}
ll f(ll n) {
ll len=0;
while(n) {
    digit[++len]=n%10;
    n/=10;
}
return dfs(len,0,1,1);
}
int main() {
    ll n,m,i,k,t;
    k=0;
    for(i=1;i<=2520;i++)
    if(2520%i==0)
     fp[i]=++k;//离散化
   // prllf("%d\n",k);
    memset(dp,-1,sizeof(dp));
    scanf("%I64d",&t);
    while(t--) {
         scanf("%I64d%I64d",&n,&m);
        printf("%I64d\n",f(m)-f(n-1));
    }
return 0;}

时间: 2024-11-10 01:40:45

cf 55D 数位dp 好题的相关文章

数位DP入门题 hdu 2089 hdu 3555

hdu 2089 不要62 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 题意:对于每次给出的一个区间,找出区间内多少个数字没有出现62和4. 思路: 数位DP入门题,对于dfs设置3个参数. 一个表示现在进行到第几位, 一个表示前一个标记状态,这里表示上一位是不是6. 一个表示是否现在是这位可以取到的最大的数字. 如果上一位是6,那么这位不可以取2.且当前位都不可以取4. 1 #include <bits/stdc++.h> 2 us

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

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

HDU 2089 不要62 (数位dp水题)

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 32358    Accepted Submission(s): 11514 题目链接 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样

bzoj 1026 [SCOI2009]windy数——数位dp水题

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1026 迷恋上用dfs写数位dp了. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=15; int l,r,dg[N],dp[N][N]; int dfs(int p,int lst,bo

HDU 2089 不要62【数位DP入门题】

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 56193    Accepted Submission(s): 21755 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可

hdu3555 Bomb (数位dp入门题)

Bomb Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 19698    Accepted Submission(s): 7311 Problem Description The counter-terrorists found a time bomb in the dust. But this time the terrorists

hdu 3555 数位dp水题 记忆化搜索做法

#include<iostream> #include<cstring> #include<cstdio> using namespace std ; const int maxn = 20; __int64 dp[maxn][3] ;//dp[i][flag] ,flag = 2,表示已经有49,flag == 1,表示没有49,这一位是4, int bit[maxn] ;    //flag == 0, 什么都没有 __int64 dfs(int pos , int

hdu2089 数位dp水题

#include<cstdio> #include<cstring> #include<iostream> using namespace std ; const int maxn = 10 ; int dp[maxn][3];//0什么都没有,1,有6,2有62或4 int bit[maxn] ; int dfs(int pos , int flag ,int lim) { if(pos == 0) return (flag !=2) ; if(dp[pos][fla

HDU3555 Bomb 数位DP第一题

The counter-terrorists found a time bomb in the dust. But this time the terrorists improve on the time bomb. The number sequence of the time bomb counts from 1 to N. If the current number sequence includes the sub-sequence "49", the power of the