hdu3555 Bomb(数位dp)
题目链接: 3555 ( Bomb )
\(dp[i][j]\) 代表首位为 \(j\) 的 \(i\) 位数中包含 \(49\) 的数的个数。
则
\[dp[i][j]=\begin{cases}0&,i = 1\\ \sum_{k=0}^9dp[i-1][k]&,i>1\and j\ne 4\\ 10^{i-2}+\sum_{k=0}^9(k\ne 9)dp[i-1][k]&,i>1\and j=4\end{cases}\\
\]
\(AC\) 代码:
/**
* hdu3555 Bomb
*
*/
#include <iostream>
#include <climits>
#include <cmath>
#include <iomanip>
#include <vector>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 20;
LL dp[N][10]; // dp[i][j]代表首位为j的i位数中包含49的个数
LL qpow(LL a, LL b, LL mod = LLONG_MAX)
{
a %= mod;
LL t = 1;
while (b) {
if (b&1) t = t*a%mod;
a = a*a%mod;
b >>= 1;
}
return t%mod;
}
void init()
{
for (int i = 2; i < N; ++i) {
for (int j = 0; j < 10; ++j) {
for (int k = 0; k < 10; ++k) {
if (j == 4 && k == 9) dp[i][j] += qpow(10, i-2);
else dp[i][j] += dp[i-1][k];
}
//cout << dp[i][j] << ' ';
}
//cout << endl;
}
}
int digit[N+1];
LL solve(LL n) // 求解[0,n]区间内包含49的数字个数
{
LL res = 0;
int len = 0;
for (LL i = n; i;) {
digit[++len] = i%10;
i /= 10;
}
//cout << '#' << len << endl;
digit[len+1] = 0;
for (int i = len; i > 0; --i) {
for (int j = 0; j < digit[i]; ++j) {
res += dp[i][j];
}
if (digit[i+1] == 4 && digit[i] == 9) {
res += n%qpow(10, i-1)+1;
break;
}
}
return res;
}
int main()
{
init();
//printf("%lld %lld\n", LLONG_MAX, solve(LLONG_MAX));
int T;
scanf("%d", &T);
while (T--) {
LL n;
scanf("%lld", &n);
printf("%lld\n", solve(n));
}
return 0;
}
因为数据范围没考虑到位 \(WA\) 了几发。