windy数(数位DP)

题目描述

w i n d y windy windy定义了一种 w i n d y windy windy数。不含前导零且相邻两个数字之差至少为 2 2 2的正整数被称为 w i n d y windy windy数。 w i n d y windy windy想知道,在 A A A B B B之间,包括 A A A B B B,总共有多少个 w i n d y windy windy数?

输入格式

包含两个整数, A A A B B B

输出格式

一个整数

S a m p l e Sample Sample I n p u t Input Input

【输入样例一】
1 1 1 10 10 10
【输入样例二】
25 25 25 50 50 50

S a m p l e Sample Sample O u t p u t Output Output

【输出样例一】
9 9 9
【输出样例二】
20 20 20

数据范围与提示

100 100 100%的数据,满足 1 ≤ A ≤ B ≤ 2000000000 1 ≤ A ≤ B ≤ 2000000000 1AB2000000000


传说中数位 D P DP DP 2 2 2种写法,但是本蒟蒻只会一种。。。


f [ i ] [ j ] f[i][j] f[i][j]表示后 i i i位,第 i i i位为j的windy数的个数
f [ i ] [ j ] = Σ f [ i − 1 ] [ k ] f[i][j] = Σf[i - 1][k] f[i][j]=Σf[i1][k]( ∣ j − k ∣ |j - k| jk > = 2 ) >= 2) >=2)


然后我们就可以去求解答案了
运用前缀和思想 l l l~ r r r中的 w i n d y windy windy数个数 = = = ( ( ( 1 1 1 ~ r r r中windy数个数) − - ( 1 1 1 ~ l − 1 l - 1 l1 w i n d y windy windy ) ) )的个数


然后,我们就可以去统计答案了
假设将一个数x分解到数位 a [ 1 ] , a [ 2 ] , … , a [ l e n ] a[1] , a[2] , … , a[len] a[1],a[2],,a[len]

  1. 位数 &lt; l e n &lt;len <len的数一定都是范围内的
  2. 位数 = l e n =len =len,首位 &lt; a [ 1 ] &lt;a[1] <a[1]的也一定是范围内的
  3. 位数 = l e n =len =len,首位 = a [ 1 ] =a[1] =a[1]的贴近上界部分直接从高位到低位枚举每一位的取值,若该位上的值与前 1 1 1位相差至少为 2 2 2则可以统计答案,若该位已经与前一位的值相差 &lt; 2 &lt;2 <2则可直接跳出循环。

代码

#include<stdio.h>
#include<cstring>
using namespace std;
const int maxn = 15;
int a[maxn];
int f[maxn][10];
int abs(int x){return x > 0 ? x : -x;}
void dp()
{
//	f[i][j]表示后i位,且第i位为j的windy数个数
//	f[i][j] = Σf[i - 1][k](abs(j - k) >= 2)
//	f[0][0] = 1
	for(int i = 0;i <= 9;i++) f[1][i] = 1;
	for(int i = 2;i <= 10;i++)
		for(int j = 0;j <= 9;j++)
			for(int k = 0;k <= 9;k++)
				if(abs(j - k) >= 2) f[i][j] += f[i - 1][k];
}
int solve(int x)//1~(x-1)中windy数的个数 
{
	int len = 0;
	for(;x;a[++len] = x % 10 , x /= 10);
	int res = 0;

	for(int i = 1;i < len;i++)
		for(int j = 1;j <= 9;j++) res += f[i][j];

	for(int i = 1;i < a[len];i++) res += f[len][i];

	for(int i = len - 1;i >= 1;i--)
	{
		for(int j = 0;j < a[i];j++)
			if(abs(j - a[i + 1]) >= 2) res += f[i][j];
		if(abs(a[i + 1] - a[i]) < 2) break;
	}
	return res;
}
int main()
{
	dp();
	int l , r;
	scanf("%d%d",&l,&r);
	printf("%d\n",solve(r + 1) - solve(l));
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值