Problem
求出 中,满足:数的长度为 ;号码中要出现至少 个相邻的相同数字;号码中不能同时出现 和 的数的个数。
。
Solution
算是一道比较简单的数位DP题。
第一个条件,根据数据范围,只需注意一点小细节就行了。
第二个,只用记录下上一个数和上一个数的上一个数,在DP的时候判断一下就行了。
第三个,用两个 记录是否出现 和 ,在最后判断一下就可以了
还有就是要注意,由于数的长度是 ,所以第一位不能填 。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int a[20];
ll f[20][20][20][2][2][2][2];
ll dp(int p,int last,int Last,bool flag,bool four,bool eight,bool limit)
{
if(!p) return flag&&(!four||!eight);
if(~f[p][last][Last][flag][four][eight][limit])
return f[p][last][Last][flag][four][eight][limit];
int i,up=limit?a[p]:9;ll ans=0;
for(i=0;i<=up;++i)
ans+=dp(p-1,i,last,flag||(i==last&&i==Last),four||i==4,eight||i==8,limit&&a[p]==i);
return f[p][last][Last][flag][four][eight][limit]=ans;
}
ll solve(ll x)
{
int i,p=0;ll ans=0;
if(x<1e10) return 0;
while(x) a[++p]=x%10,x/=10;
memset(f,-1,sizeof(f));
for(i=1;i<=a[p];++i)
ans+=dp(p-1,i,10,0,i==4,i==8,a[p]==i);
return ans;
}
int main()
{
ll l,r;
scanf("%lld%lld",&l,&r);
printf("%lld",solve(r)-solve(l-1));
return 0;
}