zoukankan      html  css  js  c++  java
  • E. Segment Sum (数位DP)

    题目:传送门

    题意:问在区间 [ L, R ] 中使用的数字不超过 k 种的数的和是多少,例如区间 [ 10, 50 ] 中使用的数字不超过 1 种的数的和是 11 + 22 + 33 + 44 = 110.

       1 <= L <= R < 1e18, 1 <= k <= 10, 输出答案对 998244353 取模。

     

    题解:显然数位DP,不过这里要算的是数的和,不是数的个数,那我们再维护一个变量就行啦,维护一下每个位上的数的贡献。

     

    #include <bits/stdc++.h>
    #define LL long long
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF INT_MAX
    #define inf LLONG_MAX
    #define PI acos(-1)
    using namespace std;
    
    const int N = 1e6 + 5, mod = 998244353;
    
    int a[20];
    int k;
    LL p[25];
    pair < LL, LL > dp[20][1 << 15];
    
    pair < LL, LL > dfs(int pos, int statu, bool zero, bool limit) {
        if(!pos) return make(__builtin_popcount(statu) <= k, 0); /// 贡献在前面已经算过
        if(!limit && !zero && dp[pos][statu].first != -1) return dp[pos][statu];
        int up = limit ? a[pos] : 9;
        pair < LL, LL > ans = make(0, 0);
        rep(i, 0, up) {
            pair < LL, LL > res;
            if(zero && i == 0) res = dfs(pos - 1, statu, zero, limit && i == up); ///前导0,这些0不算用过0.
            else res = dfs(pos - 1, statu | (1 << i), zero && i == 0, limit && i == up);
            ans.first = (ans.first + res.first) % mod;
            ans.second = (ans.second + res.second + i * res.first % mod * p[pos - 1] % mod) % mod;
        }
        if(!limit && !zero) dp[pos][statu] = ans;
        return ans;
    }
    
    LL cal(LL x) {
        int tot = 0;
        while(x) {
            a[++tot] = x % 10;
            x = x / 10;
        }
        mem(dp, -1);
        return dfs(tot, 0, 1, 1).second;
    }
    
    void solve() {
        LL l, r;
        p[0] = 1LL;
        rep(i, 1, 20) p[i] = (p[i - 1] * 10LL) % mod;
        scanf("%lld %lld %d", &l, &r, &k);
        LL ans = (cal(r) - cal(l - 1) + mod) % mod;
        printf("%lld
    ", ans);
    }
    
    int main() {
    
        solve();
    
        return 0;
    }
    一步一步,永不停息
  • 相关阅读:
    关于C#登录三层
    SQL 语句关于分页的写法
    C# 如何去掉button按钮的边框线
    20151220
    继承
    对象的旅行
    多态
    封装
    OO大原则
    javascript
  • 原文地址:https://www.cnblogs.com/Willems/p/12389841.html
Copyright © 2011-2022 走看看