【数位DP+卡常】CF401D Roman and Numbers

给一个强行套路数位dp的方法,需要卡常

题意

\(n\,(n\leq 10^{18})\)的各位数字重新排列(不允许有前导零),求可以构造几个 \(\mod m\) 等于 \(0\) 的数字。

思路

  • 读完题,一股浓烈的数位 DP 的味道。那么就开始非常套路地设计状态 \(dp_{rem,R,state}\) 表示剩余 \(rem\) 位,当前余数为 \(R\) ,剩余数的状态为 \(state\) 的合法数字个数。
    • \(state\): 一个长度为 10 的 vector,下标 i 表示数字 i 剩余多少个数。
  • 状态转移:枚举能转移到哪些数字 \(j\) ,则有

\[dp_{rem,R,state} = \sum_{j=0}^9 dp_{rem-1,new\_R, new\_state} \]

  • 解释转移变量:\(new\_R=(R\times10+j)\mod m\)\(new\_state_j = state_j-1\)
  • 然后就开始愉快的卡常数和复杂度,使用 map 会卡在 test 80,使用 unordered_map 并手写对 vector 的简单哈希函数可以通过本题 (3300ms~3800ms)。另外务必注意传参vector时加入引用。

Code

#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> PII;
typedef std::pair<ll, ll> PLL;
typedef double db;
#define re _read
#define ALL(x) (x).begin(),(x).end()
#define SZ(v) ((int)v.size())
#define fi first
#define se second
#define pb push_back
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define endl "\n"
using namespace std;
mt19937 mrand(random_device{}()); 
int rnd(int x) { return mrand() % x;}
template <typename T> std::ostream &operator<<(std::ostream &out, const std::vector<T> &v) { out << "["; bool first = true; for (auto &&e : v) { if (first) { first = false;} else {out << ", ";} out << e; } return out << "]"; }
template <typename A, typename B> std::ostream &operator<<(std::ostream &out, const std::pair<A, B> &v) {  return out << "(" << v.first << ", " << v.second << ")"; }
template <typename K> std::ostream &operator<<(std::ostream &out, const std::set<K> &s) {  out << "{"; bool first = true; for (auto &&k : s) { if (first) { first = false; } else { out << ", "; } out << k; } return out << "}"; }
template <typename K, typename V> std::ostream &operator<<(std::ostream &out, const std::map<K, V> &m) { out << "{"; bool first = true; for (auto &&[k, v] : m) { if (first) { first = false; } else { out << ", "; } out << k << ": " << v; } return out << "}"; }
template <class T> vector<vector<T>> Vector(int n, int m) { return vector<vector<T>> (n, vector<T> (m, 0)); }
template <class T> vector<vector<vector<T>>> Vector(int i, int j, int k) { return vector<vector<vector<T>>> (i, vector<vector<T>>(j, vector<T>(k, 0))); }
template <typename T> void OUT(T* a, int l, int r) { for (int i = l; i <= r; i ++) cout << a[i] << " "; puts(""); }
template<class T>
inline void _read(T& x) {
    static T ans;
    static unsigned int c;
    static bool p;
    for (c = getchar(); c != '-' && (c < '0' || c > '9'); c = getchar());
    if (c == '-') p = false, c = getchar(); else p = true;
    for (ans = 0; c <= '9' && c >= '0'; c = getchar()) ans = ans * 10 + c - '0';
    x = p ? ans : -ans;
}
/*----------------------------------------------------------------------------------------------------*/
ull Hash(vector<int>& v) {
    ull res = 0;
    for (int i = 0; i < 10; i++) {
        res = res * 100 + v[i];
    }
    return res;
}
unordered_map<ull, ll> dp[21][102];
vector<int> temp;
int m;
// rem, 
ll dfs(int rem, int R, vector<int>& s) {
    auto hval = Hash(s);
    if (dp[rem][R].count(hval)) return dp[rem][R][hval];
    ll& ans = dp[rem][R][hval];
    ans = 0;
    if (!rem) return ans = (R == 0);
    for (int i = 0; i <= 9; i++) {
        if (s[i] == 0) continue;
        s[i]--;
        ans += dfs(rem - 1, (R * 10 + i) % m, s);
        s[i]++;
    }
    return ans;
}

ll solve(ll x) {
    vector<int> d;
    while (x) {
        d.pb(x % 10);
        x /= 10;
    }
    sort(ALL(d));
    reverse(ALL(d));
    int len = SZ(d);
    vector<int> s(10, 0);
    for (int i = 0; i < len; i++) {
        s[d[i]]++;
    }
    ll ans = 0;
    int R = 0;
    for (int i = 0; i < len; i++) {
        for (int j = (i == 0 ? 1 : 0); j < d[i]; j++) {
            if (s[j] == 0) continue;
            int new_R = (R * 10 + j) % m;
            s[j]--;
            ans += dfs(len - i - 1, new_R, s);
            s[j]++;
        }
        s[d[i]]--;
        R = (R * 10 + d[i]) % m;
    }
    if (R == 0) ans++;
    return ans;
}

int main() {
    ll n;
    re(n), re(m);
    temp.resize(10, 0);
    printf("%lld\n", solve(n));
    return 0;
}
posted @ 2022-10-19 15:01  Roshin  阅读(21)  评论(0编辑  收藏  举报
-->