几道数位dp

hdu2089 不要62

/*
ID: neverchanje
PROG:
LANG: C++11
*/
#include<vector>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<set>
#include<queue>
#include<map>
using namespace std;
#define INF 1e9
#define maxn
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define mset(x) memset(x,0,sizeof(x))
typedef long long ll;
typedef pair<int,int> pii;
typedef vector<int> vi;

int n,m;
int dp[10][3];
int bit[10];
void ini(){
    mset(dp);    dp[0][1]=1;
    for(int i=1; i<=6; i++){
        dp[i][0] = dp[i-1][1];
        dp[i][1] = dp[i-1][1]*9 - dp[i-1][0];
        dp[i][2] = dp[i-1][2]*10 + dp[i-1][1] + dp[i-1][0];
    }
}
int solve(int x){
    int ans=0,len=0,tmp=x;
    bool flag=0;
    mset(bit);
    while(x){
        bit[++len] = x%10;
        x/=10;
    }
    bit[len+1]=0; //为了bit[i+1]=6 && bit[i]>2这一步
    for(int i=len;i;i--){//前i位数,第i位不为0,不吉利数为ans
        ans += dp[i-1][2]*bit[i];
        if(flag){
            ans+=dp[i-1][1]*bit[i];
            continue;
        }
        if(bit[i]>4)
            ans+=dp[i-1][1];
        if(bit[i+1]==6 && bit[i]>2)
            ans+=dp[i][0];
        if(bit[i]>6)
            ans+=dp[i-1][0];
        if((bit[i+1]==6 && bit[i]==2) || bit[i]==4)
            flag=1;
    }
    return tmp-ans;
}

int main(){
//    freopen("a.txt","r",stdin);
//    freopen(".out","w",stdout);
    ini();
    while(cin>>n>>m,n|m){
        cout<<solve(m+1)-solve(n)<<endl;
    }
    return 0;
}

/*
DESCRIPTION:
先做预处理
前i位数,不存在不吉利号码,最高位是2    dp[i][0]
.......,不存在不吉利号码,最高位包括2    dp[i][1]
.......,存在不吉利号码                  dp[i][2]
dp[i][0] = dp[i-1][1];
dp[i][1] = (dp[i-1][1]-dp[i-1][0])*9 + dp[i-1][0]*8 = dp[i-1][1]*9 - dp[i-1][0]           //最高位可以是0
dp[i][2] = dp[i-1][2]*10 + dp[i-1][0]*2 + (dp[i-1][1]-dp[i-1][0]) = dp[i-1][2]*10 + dp[i-1][0] + dp[i-1][1] 

dp[1][0] = 1;
dp[1][1] = 9;
dp[1][2] = 1;

利用solve(n)计算小于n的吉利号码的个数
ans = solve(m+1) - solve(n);

*/

hdu3555 bomb

/*
ID: neverchanje
PROG:
LANG: C++11
*/
#include<vector>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<set>
#include<queue>
#include<map>
using namespace std;
#define INF 1e9
#define maxn
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define mset(x) memset(x,0,sizeof(x))
typedef long long ll;
typedef pair<int,int> pii;
typedef vector<int> vi;

int t;
ll n;
ll dp[20][3];
int bit[20];

void ini(){
    mset(dp);
    dp[0][1]=1;
    rep(i,1,16){
        dp[i][0]=dp[i-1][1];
        dp[i][1]=10*dp[i-1][1] - dp[i-1][0];
        dp[i][2]=dp[i-1][0] + dp[i-1][2]*10;
    }
}

ll solve(ll x){
    int len=0;
    while(x){
        bit[++len] = x%10;
        x/=10;
    }
    ll ans=0;
    bool flag=0;
    bit[len+1]=0;

    for(int i=len;i;i--){
        ans+=dp[i-1][2]*bit[i];
        if(flag){
            ans+=dp[i-1][1]*bit[i];
            continue;
        }
        if(bit[i]>4)
            ans+=dp[i-1][0];
        if(bit[i+1]==4 && bit[i]==9)
            flag=1;
    }
    return ans;
}

int main(){
//    freopen("a.txt","r",stdin);
//    freopen(".out","w",stdout);
    cin>>t;
    ini();
    while(t--){
        cin>>n;
        cout<<solve(n+1)<<endl;
    }
    return 0;
}

/*
DESCRIPTION:
最高在16位

前i位,最高位为9,不存在49,dp[i][0]
.....,不存在49,dp[i][1]
.....,存在49,dp[i][2]

dp[1][0]=1
dp[1][1]=10
dp[1][2]=0

dp[i][0]=dp[i-1][1]
dp[i][1]=(dp[i-1][1]-dp[i-1][0])*10 + dp[i-1][0]*9 = 10*dp[i-1][1] - dp[i-1][0]
dp[i][2]=dp[i-1][0] + dp[i-1][2]*10

*/

hdu3652 dfs写法 含有13且是13的倍数

/*
ID: neverchanje
PROG:
LANG: C++11
*/
#include<vector>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<set>
#include<queue>
#include<map>
using namespace std;
#define INF 1e9
#define maxn
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define mset(x) memset(x,0,sizeof(x))
typedef long long ll;
typedef pair<int,int> pii;
typedef vector<int> vi;

int n;
int bit[11];
int dp[12][12][3];

int dfs(int pos, int mod, int status, bool limit){
    if(pos<=0)    return status==2 && mod==0; //含有13,且是13的倍数
    if(!limit && dp[pos][mod][status]!=-1)    return dp[pos][mod][status];// 判重
    int end=limit?bit[pos]:9, ans=0;
    for(int i=0;i<=end;i++){
        int nstatus = status;
        int nmod = (mod*10+i)%13;
        if(status==0 && i==1)
            nstatus = 1;
        else if(status==1 && i==3)
            nstatus = 2;
        else if(status==1 && i!=1)
            nstatus = 0;
        ans+=dfs(pos-1, nmod, nstatus, limit && i==end);
    }
    if(!limit)    dp[pos][mod][status] = ans;
    return ans;
}

/*
6     3     1     3     0
   pos

对于pos这一位,如果前面一位已经到了6(limit),当前pos这位就只能到3,如果前面一位小于6,当前这位就!limit

status=0 不含13, 末位不是1
status=1 不含13, 末位是1
status=2 含13

其实dfs的写法比递推的写法更具有灵活性,而且不容易写错

当!limit时,pos位之后的dp[pos][mod][status]已经被求出,则把这个值保存下来,防止重复计算
*/

int solve(int x){
    mset(bit);
    int len=0;
    while(x){
        bit[++len] = x%10;
        x/=10;
    }
    memset(dp,-1,sizeof(dp));
    return dfs(len, 0, 0, 1);
}

int main(){
    freopen("a.txt","r",stdin);
//    freopen(".out","w",stdout);
    while(cin>>n){
        cout<<solve(n+1)<<endl;
    }
    return 0;
}

/*
DESCRIPTION:

余数为j
不存在13,以3为最高位    dp[i][j][0]
不存在13    dp[i][j][1]
存在13 dp[i][j][2]

dp[i][ (dp[i-1][j][1]+3*md[i-1])%13 ][0] += dp[i-1][j][1]

dp[i][ (dp[i-1][j][0]+k*md[i-1])%13 ][1] += dp[i-1][j][1]   k=0,1,...9
dp[i][ (dp[i-1][j][0]+k*md[i-1])%13 ][1] -= dp[i-1][j][0]

dp[i][ (dp[i-1][j][0]+md[i-1])%13 ][2] += dp[i-1][j][0]
dp[i][ (dp[i-1][j][2]+k*md[i-1])%13 ][2] += dp[i-1][j][2]    k=0,1...9

*/

时间: 2024-08-07 02:14:20

几道数位dp的相关文章

手打AC的第2道数位DP:BZOJ1799: [Ahoi2009]self 同类分布

先讲下个人对于数位DP的看法吧... 挺难理解的 首先需要明白的一点:前缀和很重要 其次:必须用到记忆化搜索(本人蒟蒻,必须要用这种方法降低难度) 然后呢,需要判断约束的条件:(1.前缀0(有时需要,有时不需要):2.数位的取值(基本都需要)) 比如这道题,乍一看无思路,然后呢.... 就会出现很神奇的事情 大胆尝试(第一次)3维(题解本来是4维的...) 居然就XJB A了... 略显蛋疼... 回归正题*2: 本题的状态有些难找,但是由于数位最多的也只有pos,所以就可枚举所有的数位和...

【HDU 3652】 B-number (数位DP)

B-number Problem Description A wqb-number, or B-number for short, is a non-negative integer whose decimal form contains the sub- string "13" and can be divided by 13. For example, 130 and 2613 are wqb-numbers, but 143 and 2639 are not. Your task

HDU2089 不要62[数位DP]

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 36862    Accepted Submission(s): 13418 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可

CodeForces 55D Beautiful numbers(数位dp&amp;&amp;离散化)

题目链接:[kuangbin带你飞]专题十五 数位DP A - Beautiful numbers 题意 ps:第一道数位dp,题真好,虽然是参考大牛方法悟过才a,但仍收获不少. 求一个区间内的Beautiful numbers有多少个.Beautiful numbers指:一个数能整除所有组成它的非0数字. 例如15可以被1和5整除,所以15是Beautiful numbers. 思路 Beautiful numbers指:一个数能整除所有组成它的非0数字. 等同于 一个数能整除 所有组成它的

[bzoj1006][SCOI2009]windy数 (数位dp)

Description windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? Input 包含两个整数,A B. Output 一个整数. Sample Input [输入样例一] 1 10 [输入样例二] 25 50 Sample Output [输出样例一] 9 [输出样例二] 20 HINT [数据规模和约定] 100%的数据,满足 1 <= A <= B <= 2

hdu 4722 Good Numbers(初涉数位dp)

http://acm.hdu.edu.cn/showproblem.php?pid=4722 大致题意:若一个整数的各位数字之和是10的倍数,称这个数为"good number".给出区间[A,B],求出该区间内"good number"的数的个数. 第一道数位dp,折腾了半天才明白怎么回事. 设dp[site][mod]表示到第site位(由高位向低位)前面各位数字之和对10取余为mod的数的个数,进行记忆化搜索.有两个很重要的点,首先是变量up,表示是否到达边界

【数位dp】hdu2089 不要62

好吧,虽然是道水题但是是第一次接触数位dp所以还是要记录一下. 其实就是因为如果按数的大小枚举的话很不方便所以就按数位枚举并进行记忆化. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define s(x,y) scanf("%d%d",&x,&y) #define p(x) p

数位DP入门:bzoj1833: [ZJOI2010]count 数字计数

膜拜了一下蔡大神....然后突然想起来一些东西然后就填了一个半年多前的坑= = 人生第一道自己写的数位DP...好吧以前是看题解然后也不知道为什么就过了的>_< 数位DP介绍: http://wenku.baidu.com/link?url=9OS5Ybpw5wx00ahrH8ED2oyIlR1uWwrxT8N4pEg27GgBt2T2hLe4sd_h1rmpY7P0HmeHIEDw9h6_K98dPhhjoMhD2TpKcS8w1X8cC_dkPp_ 接下来是题目地址: http://www

hdu2089(数位DP 递推形式)

不要62 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 25802    Accepted Submission(s): 8967 Problem Description 杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer).杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以