HDU 3555 浅谈数位动态规划逆向计数问题练习

9 篇文章 0 订阅

这里写图片描述
世界真的很大
学了一小会儿数位DP,自然要找一点题来练
还是要融汇贯通才好
找到新题与原题之间的联系,辅助解题

看题先:

description:

题意就是找0到n有多少个数中含有49。数据范围接近10^20

input:

第一行一个整数T
接下来T行,每行一个整数n

output:

T行。
每行一个整数表示答案

这道题
首先dfs转移里面,需要包含前面出没出现49,上一位是什么
要考虑出没出现49,出现了几次49。。
头大。。
可能是我蠢吧
然后灵光一现,出现了49不就是总数减去没有出现49吗
这个思路类比:BZOJ 3556
然后嘛,至于求没有出现49的数,只需要保证在任何时候都不出现49就行了
这个类比 HDU 2089
这个写起来就很简单了
只需要存一下上一位是什么就行了

完整代码:

#include<stdio.h>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long dnt;

dnt f[20][20];
int a[20],T;

dnt dfs(int pos,int pre,int lim)
{
    dnt ans=0;
    if(pos==-1) return 1;
    if(!lim && f[pos][pre]!=-1) return f[pos][pre];
    int up=lim ? a[pos] : 9;
    for(int i=0;i<=up;i++)
    {
        if(pre==4 && i==9) continue;
        ans+=dfs(pos-1,i,lim && i==up);
    }
    if(!lim) f[pos][pre]=ans;
    return ans;
}

dnt solve(dnt n)
{
    int cnt=0;
    dnt tmp=n;
    memset(a,0,sizeof(a));
    while(n)
    {
        a[cnt++]=n%10;
        n/=10;
    }
    return tmp+1-dfs(cnt-1,0,1);
}

int main()
{
    scanf("%d",&T);
    memset(f,-1,sizeof(f));
    while(T--)
    {
        dnt n;
        cin >> n;
        cout << solve(n) << endl;
    }
    return 0;
}
/*
EL PSY CONGROO
*/

嗯,就是这样

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值