数位dp进阶:[CQOI2016]手机号码

我自己居然写对了!!!!

这道题目我们要充分考虑所有情况。首先要求三位连续的相同,我们开一个bool变量,来记录是否已经满足了条件。有一个小细节:

if (len<=0) return tre;

这样如果搜完了,满足条件就返回1,否则为0.

另外,4和8不能同时出现在号码中,所以开两个bool数组,来记录。同时,记忆化的细节要注意,必须满足所有条件才能return。

还有,就是第一位一定不是0,直接在一开始枚举1-num[cnt]就好了,注意如果i!=num[cnt],limit要设为0;

code:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>       
#define int long long        
using namespace std;
const int maxn=14;
int l,r,num[99],dp[maxn][maxn][maxn][maxn][2][2],cnt;
inline int dfs(int len,int firs,int sec,bool lmt,bool tre,bool eight,bool four)
{ 
    int shit=9;
    if (lmt) shit=num[len];
    int ans=0;
    if (four&&eight) return 0;
    if (len<=0) return tre;
    if (~dp[len][firs][sec][tre][eight][four]&&!lmt) return dp[len][firs][sec][tre][eight][four];
    for (int i=0;i<=shit;++i)
    {
        ans+=dfs(len-1,sec,i,lmt&&i==shit,tre||( (i==sec)&&(i==firs)),(i==8)||eight,(i==4)||four);
    }
    dp[len][firs][sec][tre][eight][four]=ans;
    return ans;
}
signed main()
{
    cin>>l>>r;
    while (r!=0)
    {
        num[++cnt]=r%10;
        r/=10;
    }
    memset(dp,-1,sizeof(dp));
    int fina1=0,fina2=0;
    for (int i=1;i<=num[cnt];++i)
    {
        fina1+=dfs(cnt-1,0,i,i==num[cnt],0,i==8,i==4);  
    }
    memset(dp,-1,sizeof(dp));
    memset(num,0,sizeof(num));
    cnt=0;  
    l--;  
    if (l>=1e10)
    {                      
        while (l!=0) 
        {
            num[++cnt]=l%10;
            l/=10;
        }   
        for (int i=1;i<=num[cnt];++i)
        {
            fina2+=dfs(cnt-1,0,i,i==num[cnt],0,i==8,i==4);  
        }   
    }
    cout<<fina1-fina2<<endl;
    return 0;
}

收获:

数位dp有三个需要斟酌的点:1、初始状态。2、判断是否合法(扫完后如果合法return 1)。3、记忆化(注意一定要满足所有条件并且limit==0才可以转移)

转载于:https://www.cnblogs.com/bullshit/p/9682208.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值