【hdu3652】数位dp(浅尝ACM-A)

这里写图片描述
向大佬学习

第一次写博客有点紧张,也算是小萌新的突破吧
这次主要是总结一下校内的ACM比赛的各种题,主要是新思路以及学到的新知识

先放一张
这里写图片描述

下面开始说正事

题面
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 is to calculate how many wqb-numbers from 1 to n for a given integer n.

Input
Process till EOF. In each line, there is one positive integer n(1 <= n <= 1000000000).

Output
Print each answer in a single line.

Sample Input
13
100
200
1000

Sample Output
1
1
2
2

乍眼一看,像极了数位dp,可是怎么判断是否能被13整除呢?之前学过做过的数位dp的限制条件都是有没有包含某数、不包含某数等。这告诉我们需要新思维了。

我们来回想一下普通的数位dp

ll dfs(int pos,,bool lead,bool limit)
{
    if(pos==-1) return 1;
    if(!limit && !lead && dp[pos][state]!=-1) return dp[pos][state];  

    int up=limit?a[pos]:9;
    ll ans=0; 
    for(int i=0;i<=up;i++)
    {  
        if() ...  
        else if()...  
        ans+=dfs(pos-1,,lead && i==0,limit && i==a[pos]) 
    }  
    if(!limit && !lead) dp[pos][state]=ans;  
    return ans;  
}  

其实就是记忆化搜索,其中dp[]表示第pos位的state状态,之所以可以直接调用返回,是因为不管前面的位怎么搞,只要符合第pos位的state状态,后面的情况就都定了,所以只需算一次,储存以后直接调用(limit==1要单独计算,以前就在这里挂了)

那么现在重点来了,state是一个很是重要的突破点,以前的思维就局限在“13”出现过没有,而处理能否被13整除,即为 i mod 13 == 0
所以dp数组就确定了: dp[i][j][k],i表示第i位,j=0,1,2,j=0表示还没有出现过“13”,j=1表示前一位是“1”,j=2表示已经出现了“13”,k表示当前的数mod13的值。
转移方程:
1、j=0,(1)该位为“1”,下传j=1;(2)不为“1”,下传j=0
2、j=1,(1)“3”,j=2:(2)“1”,j=1;(3)else,j=0;
3、j=2,直接下传j=2
4、k=(k*10)% 13(想想为什么)

然后就显而易见了
下面放代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;

char  a[15];
int b[15],len;
int dp[15][3][13];

int dfs(int pos,bool limit,int appr,int mod,bool lead){//注意还要判断前导零的问题
    if(pos==len+1){
        if(appr==2&&mod==0&&lead==0) return 1;
        else return 0;
    }
    if((!limit)&&dp[pos][appr][mod]!=-1) return dp[pos][appr][mod];
    int up=limit?b[pos]:9;
    int ans=0;
    for(int i=0;i<=up;i++){
        if(appr==0){
            if(i==1) ans+=dfs(pos+1,(limit==1&&i==up),1,(mod*10+i)%13,(i==0&&lead==1));
            else ans+=dfs(pos+1,(limit==1&&i==up),0,(mod*10+i)%13,(i==0&&lead==1));
        }
        if(appr==1){
            if(i==3) ans+=dfs(pos+1,(limit==1&&i==up),2,(mod*10+i)%13,(i==0&&lead==1));
            else if(i==1) ans+=dfs(pos+1,(limit==1&&i==up),1,(mod*10+i)%13,(i==0&&lead==1));
            else ans+=dfs(pos+1,(limit==1&&i==up),0,(mod*10+i)%13,(i==0&&lead==1));
        }
        if(appr==2) ans+=dfs(pos+1,(limit==1&&i==up),2,(mod*10+i)%13,(i==0&&lead==1));
    }
    if(!limit) dp[pos][appr][mod]=ans;
    return ans;
}
int main(){
    while(scanf("%s",a+1)!=EOF){
        len=strlen(a+1);
        for(int i=1;i<=len;i++){
            b[i]=a[i]-'0';
        }
        memset(dp,-1,sizeof(dp));
        int ans=dfs(1,1,0,0,1);
        printf("%d\n",ans);
    }
    return 0;
}

总结:
对数位dp有了更新的认识,各种不同的限制条件可以化为多个state,state是状态,不只是出现了什么数字而已

posted @ 2017-10-31 19:09  LinnBlanc  阅读(154)  评论(0编辑  收藏