题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5787
题目大意:
求l到r区间内,相邻k个数位两两互不相等的数的个数。
解题思路:
区间内统计符合某种数位条件的数的个数,很明显要用数位dp。由于k最大只有5,那么我们可以用当前位pos,当前位数的前四位preA,preB,preC,preD以及是否有相同的数来表示状态。
状态表示:dp[pos][preA][preB][preC][preD][same] ,preA到D分别是当前位的前一位到前四位的数的取值。same若为0表示当前位pos前面都没有相同的数位,为1相反。preA到D的取值范围都在0~9。由于需要判断是否相等,所以赋初值的时候不能设0~9,为了节省数组空间,就赋初值为10。
目标状态:当前位为0且same==0的时候
注意事项:会出现前导0的情况,且由于是找互不相等的数的个数,所以前导0情况不可忽略。我们按照判断前导0惯用的套路,设置一个first来记录是否有前导0。为1则有,为0则无,然后把first的状态一起递归下去即可。
其余细节为数位dp惯用套路,详见:
http://blog.csdn.net/qq_28302731/article/details/52173767
代码如下:
#include <iostream>
#include <string.h>
using namespace std;
long long dp[20][11][11][11][11][2];
int a[20];
int k;
long long dfs(int pos,int preA,int preB,int preC,int preD,int limit,int first,int same)
{
if(pos<1)
return same==0;
if(!first&&!limit && dp[pos][preA][preB][preC][preD][same]!=-1)
return dp[pos][preA][preB][preC][preD][same];
int End = limit? a[pos]:9;
long long ans = 0;
for(int i=0;i<=End;i++)
{
int samex=1;
if(first)//若存在前导0
{
if(k==5)//依据k的值,与前面的k-1个数位判断,若都不相等,则当前位的same为0.
if(i!=preA && i!=preB && i!=preC && i!=preD)
samex=0;
if(k==4)
if(i!=preA && i!=preB && i!=preC )
samex=0;
if(k==3)
if(i!=preA && i!=preB)
samex=0;
if(k==2)
if(i!=preA)
samex=0;
if(i==0)//而且当前位还是0,那么前导0继续保留,first位依旧为1
ans += dfs(pos-1,10,preA,preB,preC,limit&&(i==End),1,samex||same);//如果前面same已经为1了(不符合),那么即使samex为0,还是得用1递归下去
else
ans += dfs(pos-1,i,preA,preB,preC,limit&&(i==End),0,samex||same);
}
else
{
if(k==5)
if(i!=preA && i!=preB && i!=preC && i!=preD)
samex=0;
if(k==4)
if(i!=preA && i!=preB && i!=preC )
samex=0;
if(k==3)
if(i!=preA && i!=preB)
samex=0;
if(k==2)
if(i!=preA)
samex=0;
ans += dfs(pos-1,i,preA,preB,preC,limit&&(i==End),0,samex||same);
}
}
if(!limit&&!first)
dp[pos][preA][preB][preC][preD][same]=ans;
return ans;
}
long long solve(long long n)
{
int len=0;
while(n!=0)
{
a[++len]=n%10;
n /= 10;
}
long long ans=dfs(len,10,10,10,10,1,1,0);
return ans;
}
int main()
{
long long l,r;
while(cin>>l>>r>>k)
{
memset(dp,-1,sizeof(dp));
cout<<solve(r)-solve(l-1)<<endl;
}
return 0;
}