题目大意:
定义幸运数字为有
2N
位的数,并且前
N
位和后
定义近似幸运数字为有
2N
位的数,改动其中一位后(不能出现前导零,并且必须变动,也就是说幸运数字一定不是近似幸运数字)满足是幸运数字。
然后现在给你
A,B(A,B<=109)
,要你求出
[A,B]
中近似幸运数字的个数。
解题思路:
一道恶心的
dp
,写了我几个小时啊。。。。。。。。。
这种题目显然都是转化成求
ans([1,B])−ans([1,A−1])
,所以我们只需要考虑求
[1,K]
的情况就行了。
显然根据位数我们可以分类:
[10,99],[1000,9999],[100000,999999],[1000000,99999999]
然后如果
[1,K]
完全包含了某个区间,就直接统计把答案统计进去就行了。我们假设
K
,将某个区间给分开了,也就是说
如果
K
的位数是奇数,那么很简单,直接统计包含了几个区间就行了,因为奇数位是不可能分割以上区间的。
那么如果是偶数位,假设位数为
[102t−1,K]
,区间中有多少个近似幸运数。
我们发现,现在这个问题的区间中的数的位数都是相同的,然后我们分开考虑前
t
位和后
我们令
F1[i][j][p][q][0,1]
表示前
t
位中,
然后我们令
F2[i][j][p][q][0,1]
,
F3[i][j][p][q][0,1]
为
t+1∼t+i
中的剩下几维与
F1
中定义相同的数的个数。
然后就是三个的初值:
F1[0][0][0][0][1]=1,F2[0][0][0][0][1]=1,F3[0][0][0][0][0]=1
剩下的都是
0
,也就相当于
转移方程和输出答案详见程序吧,感觉很难讲啊。
AC代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
long long A,B;
int F[20]={0};
long long counts(int lenth,int num[])
{
long long returnd=0;
int F1[20][50][10][10][2]={{{{{0}}}}};
int F2[20][50][10][10][2]={{{{{0}}}}};
int F3[20][50][10][10][2]={{{{{0}}}}};
F1[0][0][0][0][1]=F2[0][0][0][0][1]=F3[0][0][0][0][0]=1;
for(int i=0;i<(lenth>>1);i++)
{
for(int ss=0;ss<=i*9;ss++)
{
for(int p=0;p<=9;p++)
for(int q=0;q<=9;q++)
{
for(int j=(i+1==1);j<=9;j++)
{
if(j<=num[i+1])
F1[i+1][ss+j][max(p,j-(i+1==1))][max(q,9-j)][j==num[i+1]]+=F1[i][ss][p][q][1];
F1[i+1][ss+j][max(p,j-(i+1==1))][max(q,9-j)][0]+=F1[i][ss][p][q][0];
}
}
}
}
for(int i=0;i<(lenth>>1);i++)
{
for(int ss=0;ss<=i*9;ss++)
{
for(int p=0;p<=9;p++)
for(int q=0;q<=9;q++)
{
for(int j=0;j<=9;j++)
{
if(j<=num[i+1+(lenth>>1)])
F2[i+1][ss+j][max(p,j)][max(q,9-j)][j==num[i+1+(lenth>>1)]]+=F2[i][ss][p][q][1];
F2[i+1][ss+j][max(p,j)][max(q,9-j)][0]+=F2[i][ss][p][q][0];
}
}
}
}
for(int i=0;i<(lenth>>1);i++)
{
for(int ss=0;ss<=i*9;ss++)
{
for(int p=0;p<=9;p++)
for(int q=0;q<=9;q++)
{
for(int j=0;j<=9;j++)
{
if(j<=num[i+1+(lenth>>1)])
F3[i+1][ss+j][max(p,j)][max(q,9-j)][j==num[i+1+(lenth>>1)]]+=F3[i][ss][p][q][1];
F3[i+1][ss+j][max(p,j)][max(q,9-j)][0]+=F3[i][ss][p][q][0];
}
}
}
}
for(int ss=0;ss<=(lenth>>1)*9;ss++)
{
for(int p1=0;p1<=9;p1++)
for(int q1=0;q1<=9;q1++)
for(int p2=0;p2<=9;p2++)
for(int q2=0;q2<=9;q2++)
{
int Max=max(p1,q2);
for(int g=ss+1;g<=ss+Max;g++)
{
returnd+=F1[(lenth>>1)][g][p1][q1][1]*(F2[(lenth>>1)][ss][p2][q2][0]+F2[(lenth>>1)][ss][p2][q2][1]);
returnd+=F1[(lenth>>1)][g][p1][q1][0]*F3[(lenth>>1)][ss][p2][q2][0];
}
Max=max(q1,p2);
for(int g=max(0,ss-Max);g<ss;g++)
{
returnd+=F1[(lenth>>1)][g][p1][q1][1]*(F2[(lenth>>1)][ss][p2][q2][0]+F2[(lenth>>1)][ss][p2][q2][1]);
returnd+=F1[(lenth>>1)][g][p1][q1][0]*F3[(lenth>>1)][ss][p2][q2][0];
}
}
}
return returnd;
}
long long Getans(long long K)
{
int num[20]={0};
int lenth=0;
long long returnd=0;
for(;K>0;)
{
num[++lenth]=K%10;
K/=10;
}
for(int i=2;i<lenth;i+=2)
returnd+=F[i];
reverse(num+1,num+lenth+1);
if(!(lenth&1) && lenth>0)
returnd+=counts(lenth,num);
return returnd;
}
int main()
{
F[2]=81;F[4]=7389;F[6]=676133;F[8]=62563644;
cin>>A>>B;
long long ans=Getans(B)-Getans(A-1);
cout<<ans<<endl;
return 0;
}