hdu 3652 B-number (数位DP)

来源:互联网 发布:装饰公司流水账软件 编辑:程序博客网 时间:2024/05/07 00:47

B-number

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7194    Accepted Submission(s): 4211


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 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
131002001000
 

Sample Output
1122
 

题意:
问[1,x]内有多少有子串“13”且能被13整除的数

解析:
法一(正向解):
用mod来找“13”

法二:(反向解)
(能被13整除的数)=(%13==0&&不包含“13”)+(%13==0&&包含“13”)
能被13整除的数个数=x/13
用数位DP求(%13==0&&不包含“13”)
#include<cstdio>#include<cstring>typedef long long int ll;int a[100];ll dp[100][20][3]; // k:3种操作状况,0:末尾不是1,1:末尾是1,2:含有13//0为个位,1为十位,。。。。ll dfs(int pos,bool lim,int state,int mod){if(pos==-1) return mod==0&&state==2;if(!lim&&dp[pos][mod][state]!=-1) return dp[pos][mod][state];int up=lim?a[pos]:9;ll ans=0;int tmp_mod,tmp_state;for(int i=0;i<=up;i++){tmp_mod=(mod*10+i)%13;tmp_state=state;if(state==0&&i==1)tmp_state=1;if(state==1&&i!=1)tmp_state=0;if(state==1&&i==3)tmp_state=2;ans+=dfs(pos-1,lim&&i==up,tmp_state,tmp_mod);}if(!lim) dp[pos][mod][state]=ans;return ans;}ll solve(ll n){int pos=0;while(n){a[pos++]=n%10;n=n/10;}memset(dp,-1,sizeof(dp));return dfs(pos-1,true,0,0);}int main(){int t;ll n;//scanf("%d",&t);while(scanf("%lld",&n)!=EOF){//scanf("%lld",&n);ll res=solve(n);printf("%lld\n",res);}return 0;}

法二:
#include<cstdio>#include<cstring>typedef long long int ll;int a[100];ll dp[100][20][20];  //0为个位,1为十位,。。。。ll dfs(int pos,bool limit,int state,int mod)   //计算dp[pos][state]即pos-1位是state时满足条件的个数{ll ans=0;if(pos==-1) {return mod==0;}if(!limit&&dp[pos][state][mod]!=-1) return dp[pos][state][mod];   //在非特殊情况下,直接返回之前已经算好的答案int up=limit?a[pos]:9;for(int i=0;i<=up;i++){if(state==1&&i==3)continue;ans+=dfs(pos-1,limit&&i==up,i,(mod*10+i)%13);}if(!limit) dp[pos][state][mod]= ans;  //dp只记录普通情况下的值(因为特殊情况都要重新算,不能直接返回)return ans;} ll solve(ll n){int pos=0;while(n){a[pos++]=n%10;n=n/10;}memset(dp,-1,sizeof(dp));return dfs(pos-1,true,-1,0);}int main(){int t;ll n;//scanf("%d",&t);while(scanf("%lld",&n)!=EOF){//scanf("%lld",&n);ll res=solve(n);ll k=n/13;printf("%lld\n",k-res+1);}return 0;}

原创粉丝点击