数位dp(洛谷2657)


步骤:
1.init()预处理出dp数组.dp[i][j]表示数位长度为i的最高为j的数字中的windy数的个数.则dp[i][j]=sum(dp[i-1][k]),0<=k<=9&&abs(k-j)>=2
2.写出计算[1,x]的windy数个数的函数cal(int x).
假设x为2345,则先算出[1,1000),再算[1000,2000),再算[2000,2300),[2300,2340),[2340,2345),2345.
3.求[a,b]的windy数,就是求cal(b)-cal(a-1).

主要代码:


public class Main {
	static int dp[][]=new int[20][10];
	//dp[i][j]存储位数为i的最高位为j的数字中的windy数。则dp[i][j]=sum(dp[i-1][k]),9>=k>=0,|k-j|>=2
	static void init() {//预处理出dp数组
		for(int i=0;i<=9;i++) {
			dp[1][i]=1;
		}
		for(int i=2;i<=12;i++) {
			for(int j=0;j<=9;j++) {
				for(int k=0;k<=9;k++) {
					if(Math.abs(j-k)>=2) {
						dp[i][j]+=dp[i-1][k];
					}
				}
				
			}
		}
	}
	static int cal(int x) {//计算[0,x]之间的windy数
		int res=0;
		int s[]=new int[20];
		int len=0;
		//特判,如果x=0
		if(x==0) {
			return 0;
		}
		while(x>0) {
			s[++len]=x%10;
			x/=10;
		}
		//例如x=2345,先算出[1,1000)的windy数
		for(int i=1;i<len;i++) {
			for(int j=1;j<=9;j++) {
				res+=dp[i][j];
			}
		}
		//计算[1000,2000)的
		for(int i=1;i<s[len];i++) {
			res+=dp[len][i];
		}
		
		//计算[2000,2345]的
		for(int i=len-1;i>=1;i--) {
			for(int j=0;j<s[i];j++) {
				if(Math.abs(j-s[i+1])>=2) {
					res+=dp[i][j];
				}
			}
			//判断2345是不是windy数
			if(i==1&&Math.abs(s[i]-s[i+1])>=2) {
				res+=1;
			}
			//如果当前位与高一位相差不超过2,直接break;
			if(Math.abs(s[i]-s[i+1])<2) {
				break;
			}
		}
		return res;
	}
	public static void main(String args[]) {
		InputReader sc=new InputReader(System.in);
		PrintWriter out=new PrintWriter(System.out);
		int a,b;
		a=sc.nextInt();
		b=sc.nextInt();
		init();
		int res=cal(b)-cal(a-1);
		out.println(res);
		out.flush();
		out.close();
	}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值