• 【LG4067】[SDOI2016]储能表


    【LG4067】[SDOI2016]储能表

    题面

    洛谷

    题解

    这种$n$、$m$出奇的大的题目一看就是数位$dp$啦

    其实就是用一下数位$dp$的套路

    设$f[o][n][m][k]$表示当前做到第$i$位卡不卡$n,m,k$的界

    其中$f$是个$pair$一维存方案数、一位存数值

    然后按照普通套路$dfs$即可

    代码

    #include <iostream> 
    #include <cstdio> 
    #include <cstdlib> 
    #include <cstring> 
    #include <cmath> 
    #include <algorithm>
    #include <vector> 
    using namespace std; 
    
    template <typename T> 
    void read(T &x) { 
        int op = 1; x = 0; char ch = getchar(); 
        while (!isdigit(ch)) { if (ch == '-') op = -1; ch = getchar(); } 
        while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar(); 
        x *= op; 
    }
    typedef long long ll; 
    typedef pair<ll, ll> P; 
    ll N, M, K, Mod;
    int mx; 
    P f[70][2][2][2]; 
    bool vis[70][2][2][2]; 
    void pls(ll &x, ll y) { x += y; if (x >= Mod) x -= Mod; } 
    P dfs(int o, bool n, bool m, bool k) { 
        if (o > mx) return make_pair(1, 0); 
        if (vis[o][n][m][k]) return f[o][n][m][k]; 
        vis[o][n][m][k] = 1;
        int lim_n = n ? ((N >> mx - o) & 1) : 1, lim_m = m ? ((M >> mx - o) & 1) : 1, lim_k = k ? ((K >> mx - o) & 1) : 1; 
        for (int i = 0; i <= lim_n; i++)
            for (int j = 0; j <= lim_m; j++) {
                if (k && lim_k > (i ^ j)) continue; 
                P p = dfs(o + 1, n && (i == lim_n), m && (j == lim_m), k && ((i ^ j) == lim_k)); 
                pls(f[o][n][m][k].first, p.first); 
                pls(f[o][n][m][k].second, ((1ll << mx - o) * (i ^ j) % Mod * p.first % Mod + p.second) % Mod); 
            }
        return f[o][n][m][k]; 
    } 
    int main () {
        int T; read(T); 
        while (T--) { 
            read(N), read(M), read(K), read(Mod); 
            memset(vis, 0, sizeof(vis)); 
            memset(f, 0, sizeof(f));  
            N--, M--; ll n = N, m = M, k = K; int res = 0; mx = 0; 
            while (n) ++res, n >>= 1ll; mx = max(mx, res), res = 0;   
            while (m) ++res, m >>= 1ll; mx = max(mx, res), res = 0; 
            while (k) ++res, k >>= 1ll; mx = max(mx, res); 
            P ans = dfs(1, 1, 1, 1); 
            printf("%lld
    ", (1ll * ans.second - 1ll * K % Mod * ans.first  % Mod + Mod) % Mod); 
        } 
        return 0; 
    } 
    
  • 相关阅读:
    【汇编程序】出地址为BUF的5个字符数组的内容之和
    Ugly Number
    Best Time to Buy and Sell Stock IV****
    Best Time to Buy and Sell Stock III
    Best Time to Buy and Sell Stock
    Best Time to Buy and Sell Stock II
    House Robber II
    Contain Duplicate III*******
    Contain Duplicate II
    Contain Duplicate
  • 原文地址:https://www.cnblogs.com/heyujun/p/10226345.html
Copyright © 2020-2023  润新知