类型:
数位DP
题意:求1~N内,含有49这个子串的数的个数。N<2^63-1
思路:基础数位DP。第一次做。
dp[i][d] 表示d开头的i位数中,不含49子串的个数
dp[i][d] = ∑dp[i-1][k] (0<=k<=9 && !(d==4 && k==9))
之后求0~N之间不包含49这个子串个数的做法是:
从最高位开始比较,ans += ∑dp[本位][0 ~ (N在本位的数 - 1)]
然后判断,如果本位如果取这个数,是否破坏规则(即包含49),如果是,跳出。
最后,如果N这个数本身不破坏规则,ans++。(算上本身)
最后的答案就是(N+1)-ans // 加1是因为爱,,不,是因为0.
坑点:杭电 I64d .. 做题少啊~~~
代码:
#include <cstdio> #include <cstring> #include <iostream> using namespace std; long long dp[100][10]; int num[30]; void init() { for (int i = 0; i < 10; i++) { dp[1][i] = 1; } for (int i = 2; i <= 50; i++) { for (int d = 0; d < 10; d++) { dp[i][d] = 0; for (int k = 0; k < 10; k++) { if (d == 4 && k == 9) continue; dp[i][d] += dp[i-1][k]; } } } } int main() { int t; scanf("%d", &t); init(); while (t--) { long long N; cin>>N; long long ans = 0; long long tmp = N; int len = 0; while (tmp) { num[++len] = tmp%10; tmp/=10; } bool ok = true; for (int j = 0; j <= num[len]-1; j++) { ans += dp[len][j]; } for (int i = len-1; i >= 1; i--) { for (int j = 0; j <= num[i]-1; j++) { ans += dp[i][j]; } if (num[i+1] == 4 && num[i] == 9) { ok = false; break; } } if (ok) ans++; cout<<N+1-ans<<endl; } return 0; }