ferinの競プロ帳

競プロについてのメモ

JAG2018 Day2 D - Knapsack And Queries

問題ページ

ナップサック問題のように \text{dp} \lbrack 重みがi \rbrack =最大の価値 としたDPテーブルを更新することを考える.このDPテーブルに (w,v) となるクッキーを追加する場合,chmax(dp[(i+w)%mod], dp[i]+v) となる.クッキーを追加する順番にかかわらずDPの結果は同じであり,この操作は結合的である.

ADD操作ならば最後の要素として追加,REMOVE操作ならば最初の要素を削除したい.この操作はSWAgを用いることで達成できる.

FIND操作では前半のstackのDP配列 a と後半のstackのDP配列 b をマージする必要がある.ans = \max_{l \lt =(i+j)\%MOD \lt =r} a \lbrack i \rbrack  + b \lbrack j \rbrack となるので,b \lbrack j \rbrack を固定したときの a \lbrack i \rbrack 区間maxが求められればよい.これはSWAgで達成でき,マージが O(MOD) となる.

制約が本質

#include <bits/stdc++.h>  
using namespace std;  
using ll = long long;  
using PII = pair<ll, ll>;  
#define FOR(i, a, n) for (ll i = (ll)a; i < (ll)n; ++i)  
#define REP(i, n) FOR(i, 0, n)  
#define ALL(x) x.begin(), x.end()  
template<typename T> void chmin(T &a, const T &b) { a = min(a, b); }  
template<typename T> void chmax(T &a, const T &b) { a = max(a, b); }  
struct FastIO {FastIO() { cin.tie(0); ios::sync_with_stdio(0); }}fastiofastio;  
#ifdef DEBUG_   
#include "../program_contest_library/memo/dump.hpp"  
#else  
#define dump(...)  
#endif  
const ll INF = 1LL<<60;  
  
class Crypto {  
public:      
    Crypto() {  
        sm = cnt = 0;  
        seed();  
    }  
  
    int decode(int z) {  
        z ^= next();  
        z ^= (next() << 8);  
        z ^= (next() << 16);  
        z ^= (next() << 22);  
        return z;  
    }  
  
    void query(long long z) {  
        const long long B = 425481007;  
        const long long MD = 1000000007;  
        cnt++;  
        sm = ((sm * B % MD + z) % MD + MD) % MD;  
        seed();  
    }  
private:   
    long long sm;  
    int cnt;  
  
    uint8_t data[256];  
    int I, J;  
  
    void swap_data(int i, int j) {  
        uint8_t tmp = data[i];  
        data[i] = data[j];  
        data[j] = tmp;      
    }  
  
    void seed() {  
        uint8_t key[8];  
        for (int i = 0; i < 4; i++) {  
            key[i] = (sm >> (i * 8));  
        }  
        for (int i = 0; i < 4; i++) {  
            key[i+4] = (cnt >> (i * 8));  
        }  
  
        for (int i = 0; i < 256; i++) {  
            data[i] = i;  
        }  
        I = J = 0;  
  
        int j = 0;  
        for (int i = 0; i < 256; i++) {  
            j = (j + data[i] + key[i%8]) % 256;  
            swap_data(i, j);  
        }  
    }  
  
    uint8_t next() {  
        I = (I+1) % 256;  
        J = (J + data[I]) % 256;  
        swap_data(I, J);  
        return data[(data[I] + data[J]) % 256];  
    }  
};  
  
template<class T, class S, class F>  
struct SWAG {  
    // using F = function<S(S,T)>;  
    F f; S id;  
    stack<T> lt, rt;  
    stack<S> ls, rs;  
    SWAG(F f, S d) : f(f), id(d) {  
        ls.push(id);  
        rs.push(id);  
    }  
    void push_back(T x) {   
        rt.push(x);  
        rs.push(f(rs.top(), x));  
    }  
    void pop_front() {  
        if(lt.empty()) {  
            while(rt.size()) {  
                T x = rt.top(); rt.pop(); rs.pop();  
                lt.push(x);  
                ls.push(f(ls.top(), x));  
            }  
        }  
        lt.pop();  
        ls.pop();  
    }  
    template<class Q>  
    void fold(Q q) { q(ls.top(), rs.top()); }  
};  
  
int main(void) {  
    int mod, q;  
    cin >> mod >> q;  
    Crypto c;  
  
    using S = array<ll, 512>;  
    auto f = [&](S a, PII b) {  
        S ret(a);  
        REP(i, mod) chmax(ret[(i+b.first)%mod], a[i]+b.second);  
        return ret;  
    };  
    S id;  
    id[0] = 0;  
    FOR(i, 1, 512) id[i] = -INF;  
    SWAG<PII, S, decltype(f)> swag(f, id);  
  
    REP(i, q) {  
        int t, w, v, l, r;  
        cin >> t >> w >> v >> l >> r;  
        t = c.decode(t);  
        w = c.decode(w) % mod;  
        v = c.decode(v);  
        l = c.decode(l);  
        r = c.decode(r) + 1;  
  
        if(t == 1) swag.push_back(PII(w, v));  
        else swag.pop_front();  
  
        auto query = [&](S a, S b) {  
            auto f2 = [](ll x1, ll x2){ return max(x1, x2); };  
            SWAG<ll, ll, decltype(f2)> rmq(f2, -INF);  
            FOR(i, l, r) rmq.push_back(a[i]);  
            ll ans = -1;  
            for(ll i=mod; i>0; --i) {  
                // b[i] と a[j] をマージする l<=(i+j)%mod<r  
                // b[i] を固定したときの max(a[j]) をSWAgで持っておくとマージが高速  
                auto g = [&](ll y1, ll y2){ chmax(ans, max(y1,y2)+b[i%mod]); };  
                rmq.fold(g);  
                rmq.push_back(a[(r+mod-i)%mod]);  
                rmq.pop_front();  
            }  
            c.query(ans);  
            cout << ans << "\n";  
        };  
        swag.fold(query);  
    }  
    cout << flush;  
  
    return 0;  
}