数位dp初探

数位dp,用记忆化搜索写,公认:好些且无脑!!

付经典连接

http://blog.csdn.net/cmonkey_cfj/article/details/7798809

数位DP
•问题:在给定区间[A,B]内,找满足要求的数。
•要求一般和数大小无关,而与数的组成有关
•例如,递增的,1234,2579…
•         双峰的,19280,26193…
•        含49的,49, 149, 1492… 
•         整除13的,26, 39…
•麻烦在于,规模大,位数>100,不能枚举。
•并且区间往往不是整百整千,需要小心处理边界
•注意
    –记忆化搜索思路清晰
    –开适当空间(能省则省)
    –寻找合适的状态,简化计算量

当中很多的题都会维护:能否达到上线flag,因为要保证不能超区间范围




原来是用递推来写的,现在改成记忆化搜索来写(不要62)

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

int n,m,li[7];
int f[8][2];

int dfs(int j,bool state,bool limit)
{
	if (j==0) return 1;
	if (!limit && f[j][state]) return f[j][state];
	
	int up=limit ? li[j]:9,ans=0;
	
	for (int i=0;i<=up;i++)
	{
		if (i==4) continue;
		if (state && i==2) continue;
		
		ans+=dfs(j-1,i==6? true:false,limit && i==li[j]?true:false);
	}
	if (!limit) f[j][state]=ans;
	
	return ans;
}

int work(int n)
{
	memset(f,0,sizeof(f));
	memset(li,0,sizeof(li));
	int tot=0;
	while (n)
	{
		li[++tot]=n%10;
		n=n/10;
	}
	return dfs(tot,false,true);
}

int main()
{
	while (scanf("%d%d",&n,&m)!=EOF) 
	{
		if (n==0&&m==0) break;
		printf("%d\n",work(m)-work(n-1));
	}
	return 0;
}


数位dp的思路,以位为方式dp(hdu2089)

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int f[12][10],n,m;
int work(int n)
{
	int id[12];
	memset(id,0,sizeof(id));
	while (n)
	{
		id[++id[0]]=n%10;
		n=n/10;
	}
	int ans=0;
	for (int i=id[0];i>=1;i--)
	{
		for (int j=0;j<id[i];j++)
		if (j!=4&&!(id[i+1]==6&&j==2)) ans+=f[i][j];
		if (id[i]==4||(id[i]==2&&id[i+1]==6)) break; 
	}
	return ans;
}
int main()
{
	f[0][0]=1;
	for (int i=1;i<=7;i++)
		for (int j=0;j<=9;j++)
			for (int l=0;l<=9;l++)
			if (j!=4&&!(j==6&&l==2))
				f[i][j]+=f[i-1][l];

	while (scanf("%d%d",&n,&m)!=EOF)
	{
		if (n==0&&m==0) break;
		if (n>m)swap(n,m);
		printf("%d\n",work(m+1)-work(n));
	}		
	return 0;		
}


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值