数位DP模板+裸体

题意
嘟嘟讨厌38和4,给你一个区间,让你找到区间中所有让人讨厌的数字。
记忆化的数位DP
代码

#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
const int N = 1e5+10;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
int num[9];
int f[9][3];
int dfs(int pos,int state,bool flag)
{
    if(pos==0) return state==2;
    if(flag&&f[pos][state]!=-1) return f[pos][state];
    int x=flag?9:num[pos];
    int ans=0;
    for(int i=0 ; i<=x ; i++)
    {
        if(i==4||state==2||(i==8&&state==1)) ans+=dfs(pos-1,2,flag||i<x);
        else if(i==3) ans+=dfs(pos-1,1,flag||i<x);
        else ans+=dfs(pos-1,0,flag||i<x);
    }
    if(flag) f[pos][state]=ans;
    return ans;
}
int cal(int n)
{
    memset(num,0,sizeof num);
    int pos=0;
    while(n) num[++pos]=n%10,n/=10;
    return dfs(pos,0,false);
}
int main()
{
    int l,r;
    cin>>l>>r;
    while(l!=0||r!=0)
    {
        memset(f,-1,sizeof(f));
        cout<<cal(r)-cal(l-1)<<endl;
        cin>>l>>r;
    }
    return 0;
}

用DP预处理的数位DP

#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
const int N = 10;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
int f[N][10][2];
void init()
{
    f[1][4][1]=1;
    for(int i=0 ; i<N  ; i++) f[1][i][0]=1;
    f[1][4][0]=0;
    for(int i=2 ; i<N ; i++)
        for(int j=0 ; j<=9 ; j++)
            for(int k=0 ; k<=9 ; k++)
            {
                f[i][j][1]+=f[i-1][k][1];
                if(j==3)
                {
                    if(k!=8) f[i][3][0]+=f[i-1][k][0];
                    else f[i][3][1]+=f[i-1][8][0];
                }
                else if(j==4)
                {
                    f[i][4][1]+=f[i-1][k][0];
                }
                else f[i][j][0]+=f[i-1][k][0];
            }
}
int dp(int n)
{
    vector<int>nums;
    while(n) nums.push_back(n%10),n/=10;
    int ans=0;
    int pre=0;
    int state=0;
    for(int i=nums.size()-1 ; i>=0 ; i--)
    {
        int x=nums[i];
        for(int j=0 ; j<x ; j++)
        {
            ans+=f[i+1][j][1];
            if(pre==3&&j==8&&state==0) ans+=f[i+1][j][0];
            if(state) ans+=f[i+1][j][0];
        }
        if((pre==3&&x==8)||x==4) state=1;
        pre=x;
        if(!i&&state) ans++;
    }
    return ans;
}
int main()
{
    init();
    /*for(int i=1 ; i<=4 ; i++)
    {
        for(int j=0 ; j<=9 ; j++) cout<<f[i][j][1]<<" ";
        cout<<endl;
    }
    for(int i=1 ; i<=4 ; i++)
    {
        for(int j=0 ; j<=9 ; j++) cout<<f[i][j][0]<<" ";
        cout<<endl;
    }*/
    int l,r;
    cin>>l>>r;
    while(l!=0||r!=0)
    {
        cout<<dp(r)-dp(l-1)<<endl;
        //cout<<dp(l-1)<<" "<<dp(r)<<" "<<dp(r)-dp(l-1)<<endl;
        cin>>l>>r;
    }

    /*for(int i=1 ; i<=5  ; i++)
    {
        for(int j=0 ; j<=9 ; j++) cout<<f[i][j][1]<<" ";
        cout<<endl;
    }*/
    return 0;
}

第二个用DP预处理的数位DP,让我整整调了一天,细节真的太多了。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值