可以先写一个暴力 RMQ 解决 K=1 的 10 分代码,确保自己没读错题理解成字符串问题了囧。
那么 top K 可以用类似 [USACO3.1]丑数 Humble Numbers 那个题里的方法,开个堆,每次找到一个数就分裂一下塞回去。
这个题数据量足够大,询问数组的下标从 0 开始,还要询问 rmq 的位置,非常适合用我们新学习的 O(n)-O(1) RMQ 大显身手!。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | #include <lastweapon/bitwise> using namespace lastweapon; const int N = int (5e5) + 9; int s[N]; int n, K, L, R; template < typename T> struct rmq { vector<T> v; int n; static const int b = 30; // block size vector< int > mask, t; // mask and sparse table int op( int x, int y) { return v[x] < v[y] ? x : y; } // least significant set bit int lsb( int x) { return x & -x; } // index of the most significant set bit int msb_index( int x) { return __builtin_clz(1)-__builtin_clz(x); } // answer query of v[r-size+1..r] using the masks, given size <= b int small( int r, int size = b) { // get only 'size' least significant bits of the mask // and then get the index of the msb of that int dist_from_r = msb_index(mask[r] & ((1<<size)-1)); return r - dist_from_r; } rmq(){} rmq( const vector<T>& v_) : v(v_), n(v.size()), mask(n), t(n) { int curr_mask = 0; for ( int i = 0; i < n; i++) { // shift mask by 1, keeping only the 'b' least significant bits curr_mask = (curr_mask<<1) & ((1<<b)-1); while (curr_mask > 0 and op(i, i - msb_index(lsb(curr_mask))) == i) { // current value is smaller than the value represented by the // last 1 in curr_mask, so we need to turn off that bit curr_mask ^= lsb(curr_mask); } // append extra 1 to the mask curr_mask |= 1; mask[i] = curr_mask; } // build sparse table over the n/b blocks // the sparse table is linearized, so what would be at // table[j][i] is stored in table[(n/b)*j + i] for ( int i = 0; i < n/b; i++) t[i] = small(b*i+b-1); for ( int j = 1; (1<<j) <= n/b; j++) for ( int i = 0; i+(1<<j) <= n/b; i++) t[n/b*j+i] = op(t[n/b*(j-1)+i], t[n/b*(j-1)+i+(1<<(j-1))]); } // query(l, r) returns the actual minimum of v[l..r] // to get the index, just change the first and last lines of the function T query( int l, int r) { // query too small //if (r-l+1 <= b) return v[small(r, r-l+1)]; if (r-l+1 <= b) return small(r, r-l+1); // get the minimum of the endpoints // (there is no problem if the ranges overlap with the sparse table query) int ans = op(small(l+b-1), small(r)); // 'x' and 'y' are the blocks we need to query over int x = l/b+1, y = r/b-1; if (x <= y) { int j = msb_index(y-x+1); ans = op(ans, op(t[n/b*j+x], t[n/b*j+y-(1<<j)+1])); } //return v[ans]; return ans; } }; rmq< int > T; struct rec { int i, l, r, m, f; rec( int i, int l, int r) : i(i), l(l), r(r), m(T.query(l, r)) { f = s[i] - s[m]; } bool operator < ( const rec& r) const { return f < r.f; } }; int main() { #ifndef ONLINE_JUDGE freopen ( "in.txt" , "r" , stdin); //freopen("/Users/minakokojima/Documents/GitHub/ACM-Training/Workspace/out.txt", "w", stdout); #endif RD(n, K, L, R); VI a; a.PB(0); REP_1(i, n) RD(s[i]) += s[i-1], a.PB(s[i]); a.pop_back(); T = rmq< int >(a); priority_queue<rec> Q; FOR_1(i, L, n) { Q.push(rec(i, max(0, i-R), i-L)); } LL z = 0; DO(K) { auto u = Q.top(); Q.pop(); z += u.f; if (u.m != u.l) Q.push(rec(u.i, u.l, u.m-1)); if (u.m != u.r) Q.push(rec(u.i, u.m+1, u.r)); } cout << z << endl; } |