hdu3652 B-number
题目链接: 3652 ( B-number )
\(dp[i][j][r]\) 代表 \(i\) 位数、首位为 \(j\) 、模 \(13\) 余 \(r\) 、且包含 \(13\) 的数的个数。
则根据 \(i-1\) 的状态可推出 \(i\) 的状态,不同状态间余数 \(r\) 的转换要到位。
\(AC\) 代码:
/**
* hdu3652 B-number
*
*/
#include <iostream>
#include <climits>
#include <cmath>
#include <iomanip>
#include <vector>
#include <cstring>
using namespace std;
typedef long long LL;
const int N = 11;
int dp[N][10][13]; // dp[i][j][r]代表首位为j的i位数中包含13且模13余r的数的个数
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) {
for (int r = 0; r < 13; ++r) {
int rem = (r+j*qpow(10, i-1))%13;
if (j == 1 && k == 3) {
int t = qpow(10, i-2)-1;
if (t >= rem) dp[i][j][rem] += (t-rem)/13+1;
}
else dp[i][j][rem] += dp[i-1][k][r];
}
}
//cout << dp[i][j][0] << ' ';
}
//cout << endl;
}
}
int digit[N+5];
int solve(int n)
{
int res = 0;
int len = 0;
for (int i = n; i; i /= 10) {
digit[++len] = i%10;
}
digit[len+1] = 0;
int rem = 0;
for (int i = len; i; --i) {
for (int j = 0; j < digit[i]; ++j) {
if (j == 3 && digit[i+1] == 1) {
int t = qpow(10, i-1)-1;
int r = (rem+qpow(10,i-1)*j)%13;
r = (13-r)%13;
if (t >= r) res += (t-r)/13+1;
}
else res += dp[i][j][(13-rem)%13];
}
rem = (rem+qpow(10, i-1)*digit[i])%13;
if (digit[i+1] == 1 && digit[i] == 3) {
int t = n%qpow(10, i-1), r = (13-rem)%13;
if (t >= r) res += (t-r)/13+1;
break;
}
}
return res;
}
int main()
{
init();
/*
for (int i = 0; i <= 10; ++i) {
cout << i << ": ";
for (int j = i*100; j < i*100+100; ++j) {
if (j%10 == 0) cout << endl;
cout << setw(2) << solve(j) << ' ';
}
cout << endl;
}
*/
int n;
while (~scanf("%d", &n)) {
printf("%d\n", solve(n));
}
return 0;
}