一、数位 DP
你说的对,但是数位 DP 是用于解决一种数位统计类似的问题,往往数据范围很大,比如 \(10^9, 10^{12}, 10^{18}\) 甚至更大,这种 DP 一般需要记录 当前考虑到第几位,是否贴上界 / 下界,以及一些题目里的东西,需要具体题目具体分析。
二、HDU 3652 - B-number
https://acm.hdu.edu.cn/showproblem.php?pid=3652
设 \(f_{i, 0/1, 0/1, j, k}\) 表示现在考虑到第 \(i\) 位,是否贴上界,是否出现连续 \(13\),以及 \(\bmod 13\) 的值和上一位的数。
然后就直接按照模拟转移即可,没什么好说的。
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
//#define int long long
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
inline int read () {
int x = 0, f = 0;
char c = getchar ();
for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
return !f ? x : -x;
}
int awa, n, num[15], f[15][2][2][13][10];
inline void solve (int awa) {
n = 0;
memset (f, 0, sizeof f);
while (awa) {
num[++ n] = awa % 10;
awa /= 10;
}
reverse (num + 1, num + 1 + n);
f[0][1][0][0][0] = 1;
for (int i = 0;i < n; ++ i) {
for (int j = 0;j < 2; ++ j) {
for (int k = 0;k < 2; ++ k) {
for (int mod13 = 0;mod13 < 13; ++ mod13) {
for (int las = 0;las < 10; ++ las) {
for (int _ = 0;_ < 10; ++ _) {
if (j == 0) {
auto &tmp = f[i + 1][0][k | (las == 1 && _ == 3)][(mod13 * 10 + _) % 13][_];
tmp += f[i][j][k][mod13][las];
}
else {
if (_ == num[i + 1]) {
auto &tmp = f[i + 1][1][k | (las == 1 && _ == 3)][(mod13 * 10 + _) % 13][_];
tmp += f[i][j][k][mod13][las];
}
else if (_ < num[i + 1]) {
auto &tmp = f[i + 1][0][k | (las == 1 && _ == 3)][(mod13 * 10 + _) % 13][_];
tmp += f[i][j][k][mod13][las];
}
}
}
}
}
}
}
}
int ans = 0;
for (int i = 0;i < 10; ++ i) ans += f[n][0][1][0][i];
for (int i = 0;i < 10; ++ i) ans += f[n][1][1][0][i];
printf ("%d\n", ans);
return ;
}
signed main () {
int x;
while (cin >> x) solve (x);
return 0;
}
// Always keep it simple and stupid
三、洛谷 P4317 花神的数论题
https://www.luogu.com.cn/problem/P4317
设 \(f_{i, 0/1, j}\) 表示现在考虑到(二进制下的)第 \(i\) 位,是否贴上界,有 \(j\) 个 \(1\) 的方案数。
令 \(g_k = f_{n,0,k} + f_{n,1,k}\),即有 \(k\) 个 \(1\) 的数的个数。
所以答案就是:\(\prod\limits_{k}k^{g_k}\)。
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
#define int long long
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
inline int read () {
int x = 0, f = 0;
char c = getchar ();
for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
return !f ? x : -x;
}
const int mod = 10000007;
int f[55][2][55], num[55], n, awa;
inline int pow_mod (int a, int b, int p) {
int res = 1;
while (b) {
if (b & 1) res = res * a % p;
b >>= 1, a = a * a % p;
}
return res;
}
signed main () {
awa = read ();
while (awa) {
num[++ n] = awa % 2;
awa /= 2;
}
reverse (num + 1, num + 1 + n);
memset (f, 0, sizeof f);
f[0][1][0] = 1;
for (int i = 0;i < n; ++ i) {
for (int j = 0;j < 2; ++ j) {
for (int k = 0;k <= i; ++ k) {
for (int _ = 0;_ < 2; ++ _) {
if (!j) {
auto &tmp = f[i + 1][0][k + _];
tmp += f[i][j][k];
}
else {
if (_ == num[i + 1]) {
auto &tmp = f[i + 1][1][k + _];
tmp += f[i][j][k];
}
else if (_ < num[i + 1]) {
auto &tmp = f[i + 1][0][k + _];
tmp += f[i][j][k];
}
}
}
}
}
}
int ans = 1;
for (int i = 1;i < 55; ++ i) ans = ans * pow_mod (i, f[n][0][i] + f[n][1][i], mod) % mod;
printf ("%lld\n", ans);
return 0;
}
// Always keep it simple and stupid
标签:__,pbds,gnu,int,tree,做题,include,DP,数位
From: https://www.cnblogs.com/RB16B/p/17394086.html