Loading

洛谷P4067 储能表

P4067 储能表

题意:给定n,m,k,求

\[\sum_{i=0}^{n-1} \sum_{j=0}^{m-1} \mathrm{max} ((i \mathrm{xor} j)-k,0) \]

定义状态为\(f[枚举了[0,cur)位][已枚举的位中n'是否与n相同(否则更小)][m同理][k'是否与k相同(否则更大)]\)

#include <bits/stdc++.h>
#define all(x) begin(x), end(x)
#define _for(i,f,t) for (int i = (f); i < (t); ++i)
#define _rep(i,f,t) for (int i = (f); i <= (t); ++i)
#define rd(...) __VA_ARGS__; ran(__VA_ARGS__);
using namespace std;
using ll = long long;
template<class T> int size(T& x) {return int(x.size());}
template<class... A> void ran(A&... a) { (int[]){(cin>> a,0)...}; }
template<class... A> void od(A&&... a) { (int[]){(cout<< a<< ' ',0)...}; } void odn() { cout<< '\n';}
template<class T, class... A> void odn(T&& x, A&&... a) { cout<<x; (int[]){(cout<< ' '<< a,0)...}; cout<<'\n'; }
#define int ll

int P;
struct modint {
    using mint = modint;
    int x; // assume 0 <= x < P 外部最多只读,不要修改
    constexpr modint() : x(0) {}
    modint(ll x) : x(mod(x)) {}
    // modint(int x) : x(mod(x)) {}
    template<class T>
    static inline int mod(T x) { return x>=0&&x<P ? x : ((x%=P) >= 0 ? x : x + P);} // no assume
    mint &operator*=(const mint &rhs) { x = ll(x) * rhs.x % P; return *this;}
    mint &operator+=(const mint &rhs) { if ((x += rhs.x) >= P) x -= P; return *this;}
    mint &operator-=(const mint &rhs) { if ((x -= rhs.x) < 0) x += P; return *this;}
    mint &operator/=(const mint &rhs) { return *this *= rhs.inv();}
    mint operator-() const { return mint(P - x); }
    mint pow(ll b) const {mint ans(1), a(*this); for(; b; b>>=1, a *= a) if(b&1) ans *= a; return ans;}
    mint inv() const { assert(x != 0); return pow(P - 2);}
    int val() const {return x;}
    friend mint operator*(const mint &lhs,const mint &rhs){return mint(lhs) *= rhs;}
    friend mint operator+(const mint &lhs,const mint &rhs){return mint(lhs) += rhs;}
    friend mint operator-(const mint &lhs,const mint &rhs){return mint(lhs) -= rhs;}
    friend mint operator/(const mint &lhs,const mint &rhs){return mint(lhs) /= rhs;}
    friend ostream &operator<<(ostream &os, const mint &a) { return os << a.x;}
    friend istream &operator>>(istream &is, mint &a) {ll x; is>> x; a=mint(x); return is;}
};
using mint = modint;

// const int maxl = 2;
const int maxl = 60+5;

struct Node {mint num, sum;};

int dig1[maxl], dig2[maxl], dig3[maxl];
pair<bool, Node> memo[maxl][2][2][2];
// 目前枚举了[0,cur)位,lim1则都刚好贴n(否则小于k),lim2同理,lim3为是否正好贴k(否则已经超过k),组成大于k的{对数,和}
Node F(int cur, bool lim1, bool lim2, bool lim3) {
    if (cur == maxl) return Node{1, 0};
    auto& mem = memo[cur][lim1][lim2][lim3]; 
    if (mem.first) return mem.second; 
    mem.first = true;
    auto& ans = mem.second = {0,0};
    int mx1 = lim1 ? dig1[cur] : 1,
        mx2 = lim2 ? dig2[cur] : 1;
    _rep(i, 0, mx1) _rep(j, 0, mx2) {
        if (lim3 && (i^j) < dig3[cur]) continue;
        auto t = F(cur+1, lim1 && i == mx1, lim2 && j == mx2, lim3 && (i^j) == dig3[cur]);
        ans.num += t.num;
        ans.sum += (t.sum) + mint(i^j)*(1ll<<(maxl-1-cur)) * t.num;
    }
    return ans;
}
mint getpref(ll n, ll m, ll k) {
    memset(memo, 0, sizeof(memo));
    int cnt;
    memset(dig1, 0, sizeof(dig1)); cnt = maxl-1; for (auto tn=n; tn; tn /= 2) dig1[cnt--] = tn % 2;
    memset(dig2, 0, sizeof(dig1)); cnt = maxl-1; for (auto tm=m; tm; tm /= 2) dig2[cnt--] = tm % 2;
    memset(dig3, 0, sizeof(dig1)); cnt = maxl-1; for (auto tk=k; tk; tk /= 2) dig3[cnt--] = tk % 2;
    Node ans = F(0, true, true, true);
    return ans.sum - ans.num * k;
}
void solve() {
    ll rd(n, m, k); cin>> P;
    odn(getpref(n-1, m-1, k));
}

signed main() {
#ifdef _DEBUG
    freopen("i", "r", stdin);
    // freopen("o", "w", stdout);
#else
    cout.tie(0), cin.tie(0)->sync_with_stdio(0);
#endif

    int rd(T); while (T--) 
        solve();
}
讨论记忆化复杂度

在本题中,后面三维记忆话中均不可省略。

省略后的转变:不限制转移到不限制决策方法为k,限制到不限制决策a个,那么由复杂度O(1)变成\(O(a * k^{maxl})\)

因此,如果要省略记忆某一维,必须要求k=1且a不大。总结,为了方便还是全记忆化吧。

因此本题,没有一维满足这样的限制,所以都一定不可省略记忆。

如果不记忆部分变量,在多组下也不会优化时间。因为状态这样设计,必须要充分描述。可以考虑换状态设计,尽可能少limit,而将状态描述成位都任意取,并考虑减小过程变量,让过程在枚举每位中记录(见“多数据无关写法”)。

posted @ 2022-12-02 09:12  Kelatte  阅读(48)  评论(0)    收藏  举报