数位DP入门级题目(我也只会做入门级题目0 0),求n以内的数字中不含有连续的49的数字有多少个。类似于另外一题http://acm.hdu.edu.cn/showproblem.php?pid=2089,照搬代码吧。另外一题题解,N久以前发的:传送门。
先预处理,设dp[i][j]表示第i位数是j的方案数(j可以是0),不难得到dp[i][j] = sigma(dp[i-1][k])(0<=k<=9,k≠4且j≠9)。
模拟一下求和的原理,假设n = 23495,那么len = 5;第一遍循环求出来1xxxx和0xxxx的总方案数,也就是小于20000的总方案数;第二遍循环求出来20xxx和21xxx还有22xxx的总方案数;同理,第三遍求出来230xx,231xx,232xx,233xx;第四遍2340x,2341x,2342x,2343x,2344x,2345x,2346x,2347x,2348x,下一个是2349x,这个时候出现了49再求下去没有意义,于是循环终止。
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
LL dp[25][10];
int digit[20];
void init()
{
dp[0][0] = 1;
for(int i = 1; i <= 20; i++)
{
for(int j = 0; j <= 9; j++)
for(int k = 0; k <= 9; k++)
{
if(k == 9&&j == 4) continue;
dp[i][j] += dp[i-1][k];
}
}
}
void dig(LL x,int &len)
{
memset(digit,0,sizeof digit);
while(x)
{
digit[++len] = x%10;
x /= 10;
}
}
LL cal(LL n)
{
LL ans = 0;
int len = 0;
dig(n,len);
for(int i = len; i >= 1; i--)
{
for(int j = 0; j < digit[i]; j++)
{
ans += dp[i][j];
}
if(digit[i] == 9&&digit[i+1] == 4) break;
}
return ans;
}
int main()
{
init();
int T;
LL n;
cin>>T;
while(T--)
{
cin>>n;
cout<<n+1-cal(n+1)<<endl;
}
}