数位DP小小结

FZOJ Problem 2113Jason的特殊爱好

题意:x~y数字里面有多少个 1

思路:我们算法课实验题的简化版,当时我用了很麻烦的一个DP=_=

刚刚学到了很棒的姿势,记忆化DP!!

dfs(int pos ,bool end1) ;

end1==false 返回pos位后面(包含pos)任意组合有多少个 1 ;

end1==true 返回上一位是结尾,Pos以后的位受到限制组合有多少个 1 ;

大概是这样,如果数字是 4987 现在计算到 8 这个数字,end1==true,说明是49XX

XX的取值是0-87;

如果计算到当前位,如果是这位是1 ,如果没有限制,那么答案就是加上10^pos个

如果有限制,那么答案就是加上nn%(10^pos)+1 个,

如果不是结尾(也就是没有限制的),我们可以dp[pos]保存计算过的结果。

include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long long
#define ll long long
#define INF 0x3f3f3f3f
#define maxn 50010
#define eps 1e-6
#define mod 1000000007
using namespace std;

LL dp[30] ,nn ;
int bit[30] ;

LL get1(int pos)
{
    LL tt=1;
    for(int i=0;i<pos;i++)
        tt *= 10;
    return nn%tt;
}
LL get2(int pos)
{
    LL tt=1;
    for(int i=0;i<pos;i++)
        tt *= 10;
    return tt;
}
LL dfs(int pos ,bool end1)
{
    if(pos==-1)
    {
        return 0;
    }
    if(!end1&&dp[pos] != -1)
    {
        return dp[pos];
    }
    int e ,ee ;
    LL ans=0;
    if(end1) e = bit[pos] ;
    else e = 9 ;
    for(int i = 0 ; i <= e ;i++)
    {
        if(i==1){
             if(i==e)ans += get1(pos)+1;
             else ans += get2(pos) ;
        }
        ans += dfs(pos-1,(end1&&i==e)) ;
    }
    if(!end1)
    {
        dp[pos] = ans;
    }
    return ans;
}
LL getans(LL n )
{
    nn=n;
    int len=0;
    if(n<=0) return 0 ;
    while(n)
    {
        bit[len++] = n%10 ;
        n /= 10 ;
    }
    LL ans=0;
    ans = dfs(len-1,1) ;
    return ans;
}
int main()
{
    int i , j , m ,k ,T ;
    LL x,y ;
    memset(dp,-1,sizeof(dp)) ;
   // cout << getans(20)<<endl;
    while(cin >> x >> y)
    {
        y=getans(y) ;
        x=getans(x-1);
        cout << y-x<< endl;
    }
    return 0 ;
}

hdu 3555Bomb

题意:x~y数字里面有多少个49

思路:和上面做法差不多,只是多了一个状态

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long long
#define ll long long
#define INF 0x3f3f3f3f
#define maxn 50010
#define eps 1e-6
#define mod 1000000007
using namespace std;

LL dp[30][20] ,nn ;
int bit[30] ;

LL dfs(int pos ,int num ,bool end1)
{
    if(pos==-1)
    {
        return num==2 ;
    }
    if(!end1&&dp[pos][num] != -1)
    {
        return dp[pos][num];
    }
    int e,ee;
    LL ans=0;
    if(end1) e = bit[pos] ;
    else e = 9 ;
    for(int i = 0 ; i <= e ;i++)
    {
        if(num==1&&i==9)
        {
            ee=2;
        }
        else if(num==0&&i==4)
        {
            ee=1;
        }
        else if(num==1&&i != 4)
        {
            ee=0;
        }
        else ee=num ;
        ans += dfs(pos-1,ee,(end1&&i==e)) ;
    }
    if(!end1)
    {
        dp[pos][num] = ans;
    }
    return ans;
}
LL getans(LL n )
{
    nn=n;
    int len=0;
    if(n<=0) return 0 ;
    while(n)
    {
        bit[len++] = n%10 ;
        n /= 10 ;
    }
    LL ans=0;
    ans = dfs(len-1,0,1) ;
    return ans;
}
int main()
{
    int i , j , m ,k ,T ;
    LL x,y ;
    memset(dp,-1,sizeof(dp)) ;
   // cout << getans(20)<<endl;
    cin >> T ;
    while(cin >> y)
    {
        y=getans(y) ;
        cout << y<< endl;
    }
    return 0 ;
}

hdu 3709 Balanced Number

题意:x-y有多少个是平衡的,平衡的定义是,找一个支点,使得两边的重量一样

思路:  还是和上面的姿势一样,只是状态多了一些~~~

对于  dfs(int pos ,int v,int val,bool end1)

if(end1==false)表示当前计算到第pos位,选的支点为v,前面比后面的重val,后面pos位任意组合

返回的数字数目。

if(end1==true)也就是有限制了

include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#include<bitset>
#define LL long long
#define ll long long
#define INF 0x3f3f3f3f
#define maxn 50010
#define eps 1e-6
#define mod 1000000007
using namespace std;

LL dp[20][20][2000] ;
int bit[30] ;

LL dfs(int pos ,int v,int val,bool end1)
{
    if(pos==-1)
    {
        return (val==0) ;
    }
    if(!end1&&dp[pos][v][val] != -1)
    {
        return dp[pos][v][val] ;
    }
    if(val<0) return 0 ;
    int e ,ee ;
    LL ans=0;
    if(end1) e = bit[pos] ;
    else e = 9 ;
    for(int i = 0 ; i <= e ;i++)
    {
        ee = val+(pos-v)*i ;
        ans += dfs(pos-1,v,ee,(end1&&i==e)) ;
    }
    if(!end1)
    {
        dp[pos][v][val] = ans;
    }
    return ans;
}
LL getans(LL n )
{
    int len=0;
    if(n<0) return 0 ;
    while(n)
    {
        bit[len++] = n%10 ;
        n /= 10 ;
    }
    LL ans=0;
    for( int i = 0 ; i <len ;i++)
    {
        ans += dfs(len-1,i,0,1) ;
    }
    return ans-(len-1) ;
}
int main()
{
    int i , j , m ,k ,T ;
    LL x,y ;
    memset(dp,-1,sizeof(dp)) ;
    cin >> T ;
    while(T--)
    {
        cin >> x >> y ;
        y=getans(y) ;
        x=getans(x-1);
        cout << y-x<< endl;
    }
    return 0 ;
}

时间: 2024-10-13 12:19:08

数位DP小小结的相关文章

数位DP复习小结

之前学数位dp的时候底子没打扎实 虚的要死 这次正好有时间……刷了刷之前没做的题目 感觉自己脑洞不太够……比较经典的题或者见过的类似模型就能自己推出来,但是没有见过的模型就虚的要死(比如二进制数位DP) 感谢WQ的帮助,让我对数位DP的理解逐渐加深 那么我们总结一下这次做的题目…… bzoj4521 记忆化搜索即可,水爆 1 #include <cstring> 2 #include <cstdio> 3 using namespace std; 4 #define RG regi

hdu4734 数位dp + 小技巧

hdu-4734 题意:假设x的10进制数每一位分别为(AnAn-1An-2 ... A2A1),定义  F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1,求1-b中F(x)<=F(a)的数有多少个 思路:其实F(x)只是给每一个数位带上一个权值v=2^(p-1),F(x)最大是值不会超过5000,我们完全可以抛开权值来思考,写代码的时候再加上权值即可,这样思考和写草稿之类的会方便很多,不考虑每一位的权值的话即是数位的前缀和, 很容易想

数位dp小练

最近刷题的同时还得填填坑,说来你们也不信,我还不会数位dp. 照例推几篇博客: 数位DP讲解 数位dp 的简单入门 这两篇博客讲的都很好,不过代码推荐记搜的形式,不仅易于理解,还短. 数位dp的式子一般是这样的:dp[i][][]表示到第\(i\)位,而后面几维就因题而异了. 不过通用的思想就是利用前缀相减求出区间信息. 算了上题吧. [SCOI2009]windy数 这都说是数位dp入门题. 根据这题,受到影响的数只有相邻两个,因此dp[i][j]表示到第\(i\)位(从高往低)上一位的数\(

hdu 3709 数位dp(小思维)

http://acm.hdu.edu.cn/showproblem.php?pid=3709 Problem Description A balanced number is a non-negative integer that can be balanced if a pivot is placed at some digit. More specifically, imagine each digit as a box with weight indicated by the digit.

数位dp小结以及模板

这里是网址 别人的高一啊QAQ.... 嗯一般记忆化搜索是比递推好写的所以我写的都是dfs嗯......(因为我找不到规律啊摔,还是太菜.....) 显然这个东西的条件是非常的有套路..但是不管怎么样我就抄这个大佬的模板好了.... 找到合适的递推式是很重要的(都是废话) 一般数位dp都是和整除和各位数组成有关的.... 没了.....

SCUT - 289 - 小O的数字 - 数位dp

https://scut.online/p/289 一个水到飞起的模板数位dp. #include<bits/stdc++.h> using namespace std; typedef long long ll; bool notp[2000]; const int MAXS1=200; const int MAXS2=2000; int a[20]; ll dp[20][MAXS1][MAXS2]; ll dfs(int pos,int s1,int s2,bool lead,bool l

[CSP-S模拟测试]:小L的数(数位DP+模拟)

题目传送门(内部题132) 输入格式 第一行一个整数$t$. 接下来$t$行每行一个整数$n$. 输出格式 $t$行,每行一个整数表示答案. 样例 样例输入: 418182312326910521093203 样例输出: 1233 数据范围与提示 对于前$5\%$的测试数据,满足答案小于等于$1$. 对于前$20\%$的测试数据,满足答案小于等于$2$. 对于前$40\%$的测试数据,满足$n\leqslant 300,000$. 对于前$60\%$的测试数据,满足答案小于等于$3$,$n\le

hdu 4734 数位dp

http://acm.hdu.edu.cn/showproblem.php?pid=4734 Problem Description For a decimal number x with n digits (AnAn-1An-2 ... A2A1), we define its weight as F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1. Now you are given two numbers A and B, plea

【POJ3208】传说中POJ最难的数位DP?(正解AC自动机,二解数位DP,吾异与之)

题意: 多组数据,每组求第n个包含'666'的数(不能断开),如1:666,2:1666,14:6667. 题解: AC自动机解法没去想,数位DP没学,这里有一种类似于数位DP,却又与数位DP不同,我称为数位树. 数位树: 将数n如线段树一样地拆分成多个小段,进行递归处理得出答案. 本题详(lue)解: 直接看每一位应该是什么数,然后n减去相应的数,使得在下一层转换为子问题"在开头有b个连续的6时,求第a个带'666'的数".就是如此简单,如此简单!!!! 代码来啦! #include