首先应该初始化,分为dp[i][0]dp[i][1]dp[i][2],分别表示不含有49的,不含49但最高位是9的,含有49的,递推关系是dp[i][0]=dp[i-1][0]*10-dp[i-1][1];dp[i][1]=dp[i-1][0];dp[i][2]=dp[i-1][2]*10+dp[i-1][1];之后读取数字,后从高位往下看,先加上有49的那部分,如果前面已经有49了那就再把不含49的那部分也加进去,如果前面不含49,但是现在查询到的这个数大于4的话那就只加之后的以9开头且不含49的数的个数,最后再判断一下加了这个数是不是就可以包含49这个数了,要注意的是数据比较大,所以要用__int64型。
#include <stdio.h>
#include <cstring>
__int64 dp[20][3],a[20],l;
void init()
{
int i;
memset(dp,0,sizeof(dp));
dp[0][0]=1; //
for(i=1;i<20;i++)
{
dp[i][0]=(__int64)dp[i-1][0]*10-dp[i-1][1];
dp[i][1]=(__int64)dp[i-1][0];
dp[i][2]=(__int64)dp[i-1][2]*10+dp[i-1][1];
}
}
int main()
{
int i;
int t;
__int64 n;
init();
scanf("%d",&t);
while(t--)
{
memset(a,0,sizeof(a));
__int64 ans=0;
l=1;
int flag=0;
scanf("%I64d",&n);
n++; //应当注意到不加这一项的话,例如n=49时就无法取到正确的解,感觉原因像
//是因为做if(!flag&&a[i]>4)判断时把49这种可能性忽略了,加上去之后49自
//然就行了,而因为这个进位的,由于进位后dp会自动加上dp[i-1][1],所以仍然成立
while(n)
{
a[l++]=n%10;
n=n/10;
}
for(i=l-1;i>=1;i--)
{
ans+=(__int64)dp[i-1][2]*a[i];
if(flag)
ans+=(__int64)dp[i-1][0]*a[i];
if(!flag&&a[i]>4)
ans+=(__int64)dp[i-1][1];
if(a[i]==9&&a[i+1]==4)
flag=1;
}
printf("%I64d\n",ans);
}
return 0;
}