判断(0,n]之间含49的数的个数
具体做法是数位DP , 用3个DP数组分别记录第i位
dp0[i];//不含49的数的个数
dp1[i];//不含49,但第一位是9的个数
dp2[i];//含49个数
则由状态转移方程
dp0[i+1]=dp0[i]*10-dp1[i];
dp1[i+1]=dp0[i];
dp2[i+1]=dp1[i]+dp2[i]*10;
初始为1 0 0 就可以
之后处理个数,按字符串读入之后按位处理,每次递加比该数位小的应有的数,所有如果n本身就是含49的话,就要再+1。
#include <cstdio>
#include <cstring>
typedef long long ll;
const int maxn=25;
ll dp0[maxn];//不含49
ll dp1[maxn];//不含49,但第一位是9的
ll dp2[maxn];//含49
void init ()
{
dp0[0]=1;
dp1[0]=0;
dp2[0]=0;
for (int i=0 ; i<20 ; ++i)
{
dp0[i+1]=dp0[i]*10-dp1[i];
dp1[i+1]=dp0[i];
dp2[i+1]=dp1[i]+dp2[i]*10;// dp2[i]*10表示dp2[i]*9+dp2[i]好理解些
//printf("%lld %lld %lld %lld\n",dp0[i],dp1[i],dp2[i],dp0[i]+dp2[i]);
}
}
int main ()
{
init ();
char str[25];
int num[25];
int cas ;
scanf("%d",&cas);
while (cas--)
{
scanf("%s",str);
int len = strlen (str);
for (int i=0 ; i<len ; ++i)
num[i]=str[i]-48;
ll cnt=num[0]*dp2[len-1];
//printf("%lld\n",cnt);
if(num[0]>4) cnt+=dp1[len-1];
//printf("%lld\n",cnt);
bool flag=0;
for (int i=1 ; i<len ; ++i)
{
cnt+=num[i]*dp2[len-i-1];
//printf("%lld\t",cnt);
if(flag)cnt+=num[i]*dp0[len-i-1];
if(!flag) if(num[i]>4) cnt+=dp1[len-i-1];
//printf("%lld\n",cnt);
if(!flag)if(num[i-1]==4 && num[i]==9)flag=1;
}
for (int i=0 ; i<len-1 ; ++i)
if(num[i]==4 && num[i+1]==9)flag=1;
if(flag)cnt++;
printf("%I64d\n",cnt);
}
return 0;
}