2016夏季练习——dp

来源:HDU3652

数位dp

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int dp[15][13][3];
int n;
int mod[15];
//dp[n][mod][st] represents we have a n-number which mod 13==mod
//and the st means teh same thing that the highest is 1 or 3 or other

void ini(){
	memset(mod,0,sizeof(mod));
	memset(dp,0,sizeof(dp));
	mod[1]=1;
	for(int i=2;i<10;i++){
		mod[i]=(mod[i-1]*10)%13;
	}
	dp[0][0][0]=1;
	for(int i=0;i<10;i++){
		dp[1][i][0]=1;
	}
	dp[1][3][1]=1;
	for(int i=1;i<9;i++){
		for(int j=0;j<13;j++){
			for(int k=0;k<=9;k++){
				int du=(j+k*mod[i+1])%13;
				dp[i+1][du][0]+=dp[i][j][0];
				dp[i+1][du][2]+=dp[i][j][2];
				if(k==3){
					dp[i+1][du][1]+=dp[i][j][0];
				}
				if(k==1){
					dp[i+1][du][0]-=dp[i][j][1];
					dp[i+1][du][2]+=dp[i][j][1];
				}
			}
		}
	}
}
int dpfun(int n){
	int shu[15];
	memset(shu,0,sizeof(shu));
	int len=0;
	int ans=0;
	bool flag;
	flag=false;
	int pre=0;
	while(n){
		shu[++len]=n%10;
		n/=10;
	}
	//shu[len]=0;
	/*for(int i=0;i<=len;i++)
		cout<<shu[i]<<" ";
	cout<<endl;*/
	for(int i=len;i>=1;--i){
		for(int j=0;j<shu[i];++j){
			int temp=(13-(pre*10+j)*mod[i]%13)%13;
			ans+=dp[i-1][temp][2];
			if(flag||j==3&&pre%10==1)
				ans+=dp[i-1][temp][0];
			else if(j==1)
				ans+=dp[i-1][temp][1];
		}
		pre=(pre*10)+shu[i];
		if(i!=len&&shu[i+1]==1&&shu[i]==3) flag=true;
	}
	return ans;
}
int main(){
	ini();
	while(scanf("%d",&n)!=EOF){
		cout<<dpfun(n+1)<<endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值