SoundHound Programming Contest 2018 Masters Tournament 本戦 B - Neutralize
問題ページ
B - Neutralize
解法
DPをする。dp[i] = (区間[0,i]の最大値) とする。遷移について考えると
- max(dp[j]) (0<=j<=i-k)
- dp[i-1] + b[i]
- 0 (k-1<=i)
の3通りになる。上から順に区間[j,i]を0にする、i番目の薬について0にせず足す、区間[0,i]全体を0にするを表す。
ここで一番上のmaxについて愚直に求めると遷移がO(N)かかってTLEだが区間maxなのでセグメント木で高速に求められる。したがって全体でO(NlogN)で解ける。
N<=10^5を見てDPする気持ちになれない、難しすぎる
ソースコード
#include <bits/stdc++.h> using namespace std; using ll = long long; #define int ll using VI = vector<int>; using VVI = vector<VI>; using PII = pair<int, int>; #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() #define PB push_back const ll INF = (1LL<<60); const int MOD = 1000000007; template <typename T> T &chmin(T &a, const T &b) { return a = min(a, b); } template <typename T> T &chmax(T &a, const T &b) { return a = max(a, b); } template <typename T> bool IN(T a, T b, T x) { return a<=x&&x<b; } template<typename T> T ceil(T a, T b) { return a/b + !!(a%b); } template<class S,class T> ostream &operator <<(ostream& out,const pair<S,T>& a){ out<<'('<<a.first<<','<<a.second<<')'; return out; } template<class T> ostream &operator <<(ostream& out,const vector<T>& a){ out<<'['; REP(i, a.size()) {out<<a[i];if(i!=a.size()-1)out<<',';} out<<']'; return out; } int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0}; template <typename monoid> class segmentTree { public: using M = monoid; using T = typename M::value_type; int sz; vector<T> x; segmentTree(int n = 1e5) { sz = 1; while(sz < n) sz *= 2; init(); } void init() { x.assign(sz*2, M::id()); } // [a, b) T query(int a, int b, int k, int l, int r) { if(r <= a || b <= l) return M::id(); if(a <= l && r <= b) return x[k]; return M::f(query(a, b, 2*k+1, l, (l+r)/2), query(a, b, 2*k+2, (l+r)/2, r)); } T query(int a, int b) {return query(a, b, 0, 0, sz);} // 点更新 void update(int i, const T &val) { i += sz-1; x[i] = M::g(x[i], val); while(i > 0) { i = (i-1) / 2; x[i] = M::f(x[i*2+1], x[i*2+2]); } } }; template <typename T> struct max_monoid { using value_type = T; static constexpr T id() { return std::numeric_limits<T>::min(); } static T f(const T &a, const T &b) { return max(a, b); } static T g(const T &a, const T &b) { return b; } }; template <typename T> using rmq = segmentTree<max_monoid<T>>; signed main(void) { cin.tie(0); ios::sync_with_stdio(false); int n, k; cin >> n >> k; VI a(n); REP(i, n) cin >> a[i]; if(k == 1) { int ret = 0; REP(i, n) if(a[i]>0) ret+=a[i]; cout << ret << endl; return 0; } rmq<int> seg(n); VI dp(n+5, -INF); dp[0] = a[0]; seg.update(0, dp[0]); FOR(i, 1, n) { if(i >= k-1) dp[i] = 0; if(i > k) chmax(dp[i], seg.query(0, i-k+1)); chmax(dp[i], dp[i-1] + a[i]); seg.update(i, dp[i]); } cout << max(0LL, dp[n-1]) << endl; return 0; }