1587: 【例 3】Windy 数
时间限制: 1000 ms 内存限制: 524288 KB
提交数: 596 通过数: 366
【题目描述】
原题来自:SCOI 2009
Windy 定义了一种 Windy 数:不含前导零且相邻两个数字之差至少为 2 的正整数被称为 Windy 数。
Windy 想知道,在 A 和 B 之间,包括 A 和 B,总共有多少个 Windy 数?
【输入】
一行两个数,分别为A,B。
【输出】
输出一个整数,表示答案。
【输入样例】
1 10
【输出样例】
9
【提示】
样例输入 2
25 50
样例输出 2
20
数据范围与提示:
20% 的数据,满足 1≤A≤B≤106 ;
100% 的数据,满足 1≤A≤B≤2×109 。
思路:
发现自己什么都不会qwq
这只是一个很基础的板子qwq
啊啊啊ε=ε=ε=(#>д<)?
f[i][j]表示处理到第i位,第i位上的数字是j,首先在我们dfs之前要进行预处理,在预处理的时候就判断是否符合windy数定义
接下来对于所有小于x的数进行处理,因为我们的f[i][j]定义的是所有不超过上界的数,所以对于每一位都不超过x所对应的每一位的上界的数直接加上f[i][j]就可以
但是对于这样的数:有某一位达到了上界,我们就不能通过f[i][j]数组来转移,这时候应当对这样的数特殊处理,处理方式是枚举上界,枚举当前所在位上的数,如果符合windy数定义,那么就加上f[i][j](因为这个时候的确符合f[i][j]未达到上界),ans+=f[i][j]
代码:
#include<bits/stdc++.h>
#define ll long long
#define maxn 15
using namespace std;
ll a,b;
ll f[maxn][maxn];
ll p[maxn];
void prepare()
{
// f[0][0]=0;
p[0]=1;
for(int i=1;i<=13;i++) p[i]=p[i-1]*10;
for(int i=0;i<=9;i++) f[1][i]=1;
for(int i=2;i<=13;i++)
for(int j=0;j<=9;j++)
for(int k=0;k<=9;k++)
{
if(abs(k-j)>=2) f[i][j]+=f[i-1][k]/*,cout<<f[i][j]<<" "*/;
}
}
ll work(ll x)
{
ll ans=0;
// if(x==1) return 0;
ll w=0;
ll y;
while(p[w]<=x) w++;//找到比x小的位数,只要位数比x小,那么一定是答案之一
// cout<<w<<" ";
for(int i=1;i<w;i++)
for(int j=1;j<=9;j++)//从1开始是为了排除前导0
{
ans+=f[i][j];
// cout<<f[i][j]<<" ";
// cout<<ans<<‘\n‘;
}
y=x/p[w-1];//找到位数与x相同的位数上的数
ll pre=y;
// cout<<ans<<" ans1\n";
for(int i=1;i<y;i++) ans+=f[w][i]/*,cout<<ans<<‘\n‘*/;//这个数也比x小,从1开始是为了排除前导0
// cout<<ans<<" ans2\n";
x%=p[w-1];
for(int i=w-1;i>=1;i--)
{
y=x/p[i-1];
for(int j=0;j<y;j++)
if(abs(j-pre)>=2) ans+=f[i][j]/*,cout<<ans<<‘\n‘;*/;
if(abs(pre-y)<2) break;
pre=y;
x%=p[i-1];
}
// cout<<ans<<" @@@@\n";
return ans;
}
int main()
{
cin>>a>>b;
prepare();
// prepare();
//cout<<b+1<<" uuhuo "<<work(b+1)<<‘\n‘;
//cout<<a<<" kukhkuh "<<work(a)<<‘\n‘;
printf("%lld\n",work(b+1)-work(a));
return 0;
}