HDU 3652——B-number(数位DP)

48 篇文章 0 订阅

这道题参考了百度文库中的课件http://wenku.baidu.com/link?url=zZWAUhUwQPzg1s6s4N1AAi-hv3hHaVf83-Wxp4zCWGBeerEHOddF1V1miCLNrZnVvARM2vTBaWAkKqgZXx26h8SHw82-rB7wxa3rDSskZjW

题意是找到从1到n中间包含“13”以及可以被13整除的数字的个数。

dfs(len,j,k,l,flag)表示长度为len,j为第len +1位的数字是,k为是否包含13,l为膜13以后的余数,flag标记是否能够取到9。

决策第i位:

for x = 0 ~ 9
  if k = 1 //要求要包含13
    f[i,j,k,l] = f[i - 1,x,1,m];
    if j = 1 and x = 3 //已经有13了。
      f[i,j,k,l] = f[i,j,k,l] + 
                   f[i - 1,x,0,m];
  else //不要求包含13
    if not (j = 1 and x = 3) 
      f[i,j,k,l] = f[i - 1,x,0,m];

m即方程(10^(len-1)*j+n)%13=l,m=n%13的解。

在求解过程中使用记忆化搜索。

代码如下:

#include<iostream>
#include<cstring>
using namespace std;
int digit[11];
int dp[12][10][2][15];

int pow(int n,int t){
//	cout<<"pow"<<n<<' '<<t<<' ';
	if(t<=0){
	//	cout<<0<<endl;
		return 0;
	}
	int tmp=1;
	for(int i=0;i<t;++i){
		tmp*=n;
	}
//	cout<<tmp<<endl;
	return tmp;
}

int dfs(int len,int j,int k,int l,int flag){
//	cout<<"len="<<len<<' '<<"i+1digit"<<j<<' '<<"contain13="<<k<<' '<<"%13="<<l<<' '<<digit[len]<<endl;
	if(len==0){
		if(k)return 0;
		if(l>9)return 0;
		if(j!=l)return 0;
		return 1;
	}
	if(flag&&dp[len][j][k][l]!=-1)return dp[len][j][k][l];
	int ans=0;
	int fmax=flag?9:digit[len];
	int tmp;
	for(int i=0;i<=13;++i){
		if((pow(10,len)*j+i)%13==l){tmp=i;break;}
	}
//	cout<<len-1<<' '<<pow(10,len-1)*j<<' '<<"tmp="<<tmp<<endl;
	for(int i=0;i<=fmax;++i){
		if(k==1){
			ans+=dfs(len-1,i,k,tmp,flag||i<fmax);
			if(j==1&&i==3){
				ans+=dfs(len-1,i,0,tmp,flag||i<fmax);
			}
		}
		else {
			if(j==1&&i==3)continue;
			ans+=dfs(len-1,i,0,tmp,flag||i<fmax);
		}
	}
	if(flag){
		dp[len][j][k][l]=ans;
	}
	return ans;
}

int solve(int n){
	int len=0;
	while(n){
		digit[++len]=n%10;
		n/=10;
	}
	return dfs(len,0,1,0,false);
}

int main(){
//	freopen("data.txt","r",stdin);
	int n;
	memset(dp,-1,sizeof(dp));
	while(cin>>n){
		cout<<solve(n)<<endl;
	}
	return 0;
}

在第一次提交是,将dfs函数的第四个参数的含义弄错了,传参数就不对。(第一次理解成(10^(len-1)+l)%13=tmp)

改正后,提交仍然错误,原因是前面写的时候先把dfs的第二个参数定义为是否第len+1位为1,后来更正成为表示len+1位的值,然后在for循环中的else里面忘记把if(j&&i==3)continue;改成if(j==1&&i==3)continue,然后在1339的时候判断开始出错。

刚开始接触数位DP,上个星期三看了第一道数位DP,用了三天时间写出来(因为有好多课,还看了别人的题解以后参考的写的),这道题只看了一个课件的思路,写程序的时候完全没有看别人的代码,在写完以后第二个错误找不到了然后开始运行别人的代码,找到了错误的数据,想了七八个小时吧……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值