数位DP HDU3555+CF55D+HDU2089

来源:互联网 发布:淘宝商品佣金查询 编辑:程序博客网 时间:2024/05/22 21:48

数位DP:较为精细的讲解在上面的文章已经提到了,这里就直接说题了

1hdu:2089 

http://acm.hdu.edu.cn/showproblem.php?pid=2089

题意:询问[L,R]之间有多少个数没有出现过4,且不存在62相连的情况!

思路:基本的数位dp,记忆化搜索,其中dp[i]都表示的是从1到当前数的答案数,考虑每一位判断是否是4,同时记录下来前一位是否是6,如果是6则当前位不枚举2即可。

#include <iostream>#include<algorithm>#include<stdio.h>#include<string.h>using namespace std;typedef long long ll;ll dp[11][2];ll dig[15];ll dfs(int pos,int flag,int lim){    if(pos<0) return 1;    if(!lim&&dp[pos][flag]!=-1) return dp[pos][flag];    int up=lim? dig[pos]:9;    int ans=0;    for(int i=0;i<=up;++i)    {        if(i==4) continue;        if(flag&&i==2) continue;        ans+=dfs(pos-1,i==6,lim&&(i==up));    }    if(!lim) dp[pos][flag]=ans;    return ans;}ll get(ll a){    int len=0;    while(a)    {        dig[len++]=(a%10);        a/=10;    }    return dfs(len-1,0,1);}int main(){    memset(dp,-1,sizeof(dp));    ll n,m;    while(scanf("%lld%lld",&n,&m)!=EOF)    {        if(n==0&&m==0) break;        printf("%lld\n",get(m)-get(n-1));    }    return 0;}


HDU 3555

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555

题意:问在一个区间内有多少个数字出现过连续的49?

思路:和上道题基本相似,只不过问的是出现的,考虑的条件只有一个了.每次枚举判断前一位和当前位即可

#include <iostream>#include<algorithm>#include<stdio.h>#include<string.h>#include<math.h>using namespace std;typedef long long ll;ll dp[30][12][2];int dig[30];ll dfs(int pos, int pre,int flag,int limt){   if(pos<0) return flag;   if(!limt&&dp[pos][pre][flag]!=-1) return dp[pos][pre][flag];   int up=limt? dig[pos]: 9;   ll ans=0;   for(int i=0;i<=up;i++)   {       ans+=dfs(pos-1,i,flag||(pre==4&&i==9),limt&&(i==up));   }   if(!limt) dp[pos][pre][flag]=ans;   return ans;}ll get(ll num){    int len=0;    while(num)    {        dig[len++]=(num%10);        num/=10;    }    return dfs(len-1,0,0,1);}int main(){    memset(dp,-1,sizeof(dp));    int T;    scanf("%d",&T);    while(T--)    {        ll a;        scanf("%lld",&a);        printf("%lld\n",get(a));    }    return 0;}


CF55D:http://codeforces.com/problemset/problem/55/D

第一次碰到这个题是在17年陕西省赛的热身赛上。然后三个人都不会就直接GG。

题意:问在一串序列中,有多少个数可以被它每一个位数都整除?

思想:将问题可以转换为有多少个数可以被所有数位的LCM整除.(记着求LCM的时候要考虑0)

这里有个小技巧:因为这个数字会很大所以每次对它mod一个2520,因为(1-9)的最小公倍数是2520,所以每次mod2520 并不改变问题的结果。。

#include <iostream>#include<algorithm>#include<stdio.h>#include<string.h>using namespace std;typedef long long  ll;const int mod=2520;int ls[mod+10];ll dp[20][mod+10][50];int dig[30];ll dfs(int pos,int sum,int lcm,int lim){    if(pos<0) return sum%lcm==0;    if(!lim&&dp[pos][sum][ls[lcm]]!=-1) return dp[pos][sum][ls[lcm]];    int up=lim? dig[pos]:9;    ll ans=0;    for(int i=0;i<=up;++i)    {        if(i==0)            ans+=dfs(pos-1,(sum*10+i)%mod,lcm,lim&&(i==up));        else            ans+=dfs(pos-1,(sum*10+i)%mod,lcm*i/__gcd(lcm,i),lim&&(i==up));    }    if(!lim) dp[pos][sum][ls[lcm]]=ans;    return ans;}ll get(ll a){    int len=0;    while(a)    {        dig[len++]=(a%10);        a/=10;    }    return dfs(len-1,0,1,1);}int main(){    memset(dp,-1,sizeof(dp));    int cnt=0;    for(int i=1;i<=mod;++i)    {        if(mod%i==0) ls[i]= (++cnt);    }    int T;    scanf("%d",&T);    while(T--)    {        ll l,r;        scanf("%I64d%I64d",&l,&r);        printf("%I64d\n",get(r)-get(l-1));    }    return 0;}





原创粉丝点击