hdu 3652 B-number (数位DP)

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
 
   
13 100 200 1000
 

Sample Output
 
   
1 1 2 2
 

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

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

法二:(反向解)
(能被13整除的数)=(%13==0&&不包含“13”)+(%13==0&&包含“13”)
能被13整除的数个数=x/13
用数位DP求(%13==0&&不包含“13”)
#include
#include

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
#include

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;

}

你可能感兴趣的:(数位DP)