SCOI2009
Windy数【四川省选2009】
题目背景
题目描述
Windy 定义了一种 Windy 数。
不含前导零且相邻两个数字之差至少为 2 的正整数被称为 Windy 数。
Windy 想知道,在 A 和 B 之间,包括 A 和 B,总共有多少个 Windy 数?
输入格式
输入文件包含两个整数,A B。
输出格式
输出文件包含一个整数即 Windy 数的个数。
样例数据 1
样例数据 2
备注
【数据范围】
20% 的数据,满足:1<=A<=B<=1000000 。
100% 的数据,满足:1<=A<=B<=2000000000 。
解题报告:
数位型动态规划。
设函数 tt(x) 表示小于 x 的 windy 数的个数。
那么答案为 tt(B+1)-tt(A)。
z[i][j]表示当前还有 i 个数字可用,当前数字为 j 的方案数。
z[i][j]=sum(z[i-1][k])(abs(j-k)>=2)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=11;
int a,b,f[N][N][2],c[N][N];
inline int dp(int x)
{
static int aa[N];
int n=0;
while(x) aa[++n]=x%10,x/=10;
if(n==0) aa[++n]=0;
memset(f,0,sizeof(f));
for(int i=0;i<=9;++i)
if(i<=aa[1]) f[1][i][0]=1;
else f[1][i][1]=1;
for(int i=2;i<=n;++i)
for(int j=0;j<=9;++j)
for(int k=0;k<=9;++k)
if(c[j][k]>=2)
{
if(j<aa[i])
f[i][j][0]+=f[i-1][k][0]+f[i-1][k][1];
else if(j==aa[i])
f[i][j][0]+=f[i-1][k][0],f[i][j][1]+=f[i-1][k][1];
else f[i][j][1]+=f[i-1][k][0]+f[i-1][k][1];
}
int res=0;
for(int i=1;i<=9;++i)
{
if(i<aa[n]) res+=f[n][i][0]+f[n][i][1];
else if(i==aa[n]) res+=f[n][i][0];
}
for(int i=n-1;i;--i)
for(int j=1;j<=9;++j)
res+=f[i][j][0]+f[i][j][1];
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
for(int i=0;i<=9;++i)
for(int j=i;j<=9;++j)
c[i][j]=c[j][i]=j-i;
cin>>a>>b;
cout<<dp(b)-dp(a-1)<<endl;
return 0;
}