分析: dp+线段树优化 我表示不会 copy一遍题解
首先题目给出的城市坐标不是按X轴升序的, 那么我们就将每个城市根据坐标从左到右映射到X轴上的1~n
设dp[i]:= 到第 i 个点(包括第i个点)时, 处理掉前面所有必须不连通的道路的最小花费。
由于道路可能存在包含关系, 此时必定是选取最右边的左端点L作为区间左端点(假设每条道路从左端点开始, 右端点结束)
否则选取其他的点只会徒增花费
那么 dp[i] = min{dp[j] + len( j , j+1) }, L <= j < i, 其中len(j , j+1) 表示映射到坐标轴上的城市的距离
我们用线段树来维护dp[j] + len( j , j+1) 的最小值 每次处理完后将dp[i] + len (i, i+1) 插入到i
然后就可以ac了
代码:
// // Created by TaoSama on 2015-09-21 // Copyright (c) 2015 TaoSama. All rights reserved. // //#pragma comment(linker, "/STACK:1024000000,1024000000") #include <algorithm> #include <cctype> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iomanip> #include <iostream> #include <map> #include <queue> #include <string> #include <set> #include <vector> using namespace std; #define pr(x) cout << #x << " = " << x << " " #define prln(x) cout << #x << " = " << x << endl const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7; int minv[N << 2]; #define root 1, n, 1 #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 void push_up(int rt) { minv[rt] = min(minv[rt << 1], minv[rt << 1 | 1]); } void update(int o, int v, int l, int r, int rt) { if(l == r) { minv[rt] = v; return; } int m = l + r >> 1; if(o <= m) update(o, v, lson); else update(o, v, rson); push_up(rt); } int query(int L, int R, int l, int r, int rt) { if(L <= l && r <= R) return minv[rt]; int m = l + r >> 1, ret = INF; if(L <= m) ret = min(ret, query(L, R, lson)); if(R > m) ret = min(ret, query(L, R, rson)); return ret; } int n, k, a[N], all[N], pre[N]; int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); // freopen("out.txt","w",stdout); #endif ios_base::sync_with_stdio(0); while(scanf("%d%d", &n, &k) == 2) { memset(minv, 0x3f, sizeof minv); memset(pre, 0, sizeof pre); for(int i = 1; i <= n; ++i) { scanf("%d", a + i); all[i] = a[i]; } sort(all + 1, all + 1 + n); for(int i = 1; i <= k; ++i) { int l, r; scanf("%d%d", &l, &r); l = lower_bound(all + 1, all + 1 + n, a[l]) - all; r = lower_bound(all + 1, all + 1 + n, a[r]) - all; if(l > r) swap(l, r); pre[r] = max(pre[r], l); } int pos = 0, ans = 0; for(int i = 1; i <= n; ++i) { pos = max(pos, pre[i]); if(pos && i > 1) ans = query(pos, i - 1, root); if(i < n) update(i, ans + all[i + 1] - all[i], root); } printf("%d\n", ans); } return 0; }
题意: 每个ACMer有能力, 价格, 每个题目有难度 现在小Z有L钱 问怎么请ACMer才能最少的天数完成
分析: 贪心啦 红果果的set贪心 将ACMer和题目按照 能力、难度大到小排序 先搞大的 大的都不能搞还搞毛
把可以解决当前题目的ACMer都丢进set里 然后找一个最便宜的 如此贪心
天数二分就可以了 能干掉这个题 继续干掉比它小的天数-1个题
代码: 据说PQ会快点 set习惯了
// // Created by TaoSama on 2015-09-21 // Copyright (c) 2015 TaoSama. All rights reserved. // //#pragma comment(linker, "/STACK:1024000000,1024000000") #include <algorithm> #include <cctype> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iomanip> #include <iostream> #include <map> #include <queue> #include <string> #include <set> #include <vector> using namespace std; #define pr(x) cout << #x << " = " << x << " " #define prln(x) cout << #x << " = " << x << endl const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7; int n, m, l, ans[N]; struct ACM { int a, c, id; bool operator< (const ACM& rhs) const { return a > rhs.a; } } A[N], B[N]; typedef pair<int, int> P; bool check(int x) { set<P> s; int cost = 0; for(int i = 1, j = 1; i <= m;) { while(j <= n && A[j].a >= B[i].a) s.insert(P(A[j].c, A[j].id)), j++; if(!s.size()) return false; cost += s.begin()->first; if(cost > l) return false; int t = x, id = s.begin()->second; s.erase(s.begin()); while(t-- && i <= m) ans[B[i++].id] = id; } return true; } int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); // freopen("out.txt","w",stdout); #endif ios_base::sync_with_stdio(0); while(scanf("%d%d%d", &n, &m, &l) == 3) { for(int i = 1; i <= n; ++i) scanf("%d", &A[i].a); for(int i = 1; i <= n; ++i) scanf("%d", &A[i].c), A[i].id = i; for(int i = 1; i <= m; ++i) scanf("%d", &B[i].a), B[i].id = i; sort(A + 1, A + 1 + n); sort(B + 1, B + 1 + m); int l = 0, r = 1e5; while(l <= r) { int m = l + r >> 1; if(check(m)) r = m - 1; else l = m + 1; } if(check(l)) { puts("Good Luck"); for(int i = 1; i <= m; ++i) printf("%d%c", ans[i], " \n"[i == m]); } else puts("Do it yourself"); } return 0; }
题意: 求连续的最大矩形
分析: 单调栈或者dp维护从i这个位置能向左右延伸的最大值 不同的是单调栈是() dp是[]
代码:
// // Created by TaoSama on 2015-09-21 // Copyright (c) 2015 TaoSama. All rights reserved. // //#pragma comment(linker, "/STACK:1024000000,1024000000") #include <algorithm> #include <cctype> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iomanip> #include <iostream> #include <map> #include <queue> #include <stack> #include <string> #include <set> #include <vector> using namespace std; #define pr(x) cout << #x << " = " << x << " " #define prln(x) cout << #x << " = " << x << endl const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7; int n, a[N]; int l[N], r[N]; int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); // freopen("out.txt","w",stdout); #endif ios_base::sync_with_stdio(0); while(scanf("%d", &n) == 1) { for(int i = 1; i <= n; ++i) scanf("%d", a + i); stack<int> s; for(int i = 1; i <= n; ++i) { while(s.size() && a[s.top()] >= a[i]) s.pop(); l[i] = s.size() ? s.top() : 0; s.push(i); } while(s.size()) s.pop(); for(int i = n; i >= 1; --i) { while(s.size() && a[s.top()] >= a[i]) s.pop(); r[i] = s.size() ? s.top() : n + 1; s.push(i); } long long ans = 0; for(int i = 1; i <= n; ++i) ans = max(ans, 1LL * a[i] * (r[i] - l[i] - 1)); printf("%lld\n", ans); } return 0; }
题意: 长度为N的环 求长度不超过M的最大连续和以及位置 多解输出最短的优先 然后字典序小的优先
分析: 线段树区间合并 直接维护答案直接搞 倍增一下查询N次M大小的区间 更新答案就好
代码:
// // Created by TaoSama on 2015-09-21 // Copyright (c) 2015 TaoSama. All rights reserved. // //#pragma comment(linker, "/STACK:1024000000,1024000000") #include <algorithm> #include <cctype> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iomanip> #include <iostream> #include <map> #include <queue> #include <string> #include <set> #include <vector> using namespace std; #define pr(x) cout << #x << " = " << x << " " #define prln(x) cout << #x << " = " << x << endl const int N = 2e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7; int n, k, a[N]; #define root 1, n, 1 #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 typedef pair<int, int> Interval; struct Node { int l, r; int preR, sufL; Interval sub; } dat[N << 2]; int sum(const Interval& x) { return a[x.second] - a[x.first - 1]; } Interval getMax(const Interval& x, const Interval& y) { int sx = sum(x), sy = sum(y); if(sx != sy) return sx > sy ? x : y; int dx = x.second - x.first, dy = y.second - y.first; if(dx != dy) return dx < dy ? x : y; return x < y ? x : y; } Node push_up(const Node& x, const Node& y) { Node ret; ret.l = x.l; ret.r = y.r; ret.preR = getMax(Interval(x.l, x.preR), Interval(x.l, y.preR)).second; ret.sufL = getMax(Interval(y.sufL, y.r), Interval(x.sufL, y.r)).first; ret.sub = getMax(Interval(x.sufL, y.preR), getMax(x.sub, y.sub)); return ret; } void build(int l, int r, int rt) { if(l == r) { dat[rt].l = dat[rt].r = l; dat[rt].preR = dat[rt].sufL = l; dat[rt].sub = Interval(l, l); return; } int m = l + r >> 1; build(lson); build(rson); dat[rt] = push_up(dat[rt << 1], dat[rt << 1 | 1]); } Node query(int L, int R, int rt) { if(L <= dat[rt].l && dat[rt].r <= R) return dat[rt]; int m = dat[rt].l + dat[rt].r >> 1; Node ret; if(L <= m && R > m) return push_up(query(L, R, rt << 1), query(L, R, rt << 1 | 1)); else if(L <= m) ret = query(L, R, rt << 1); else if(R > m) ret = query(L, R, rt << 1 | 1); return ret; } int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); // freopen("out.txt","w",stdout); #endif ios_base::sync_with_stdio(0); while(scanf("%d%d", &n, &k) == 2) { for(int i = 1; i <= n; ++i) { scanf("%d", a + i); a[i + n] = a[i]; } n <<= 1; for(int i = 1; i <= n; ++i) a[i] += a[i - 1]; build(root); Interval ans(1, 1); n >>= 1; for(int i = 1; i <= n; ++i) ans = getMax(ans, query(i, i + k - 1, 1).sub); printf("%d %d %d\n", sum(ans), (ans.first - 1) % n + 1, (ans.second - 1) % n + 1); } return 0; }分析: 考虑最大连续和=整个序列的前缀和-当前M大小区间的最小前缀和
我们维护一个M+1大小的单调队列 - - 多一个好写代码 减的时候把这个多的减掉就好了
注意特判全为负数的情况 样例很强就不多说了
代码:
// // Created by TaoSama on 2015-09-22 // Copyright (c) 2015 TaoSama. All rights reserved. // //#pragma comment(linker, "/STACK:1024000000,1024000000") #include <algorithm> #include <cctype> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iomanip> #include <iostream> #include <map> #include <queue> #include <string> #include <set> #include <vector> using namespace std; #define pr(x) cout << #x << " = " << x << " " #define prln(x) cout << #x << " = " << x << endl const int N = 2e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7; int n, k; int a[N]; int deq[N], deqv[N]; int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); // freopen("out.txt","w",stdout); #endif ios_base::sync_with_stdio(0); while(scanf("%d%d", &n, &k) == 2) { for(int i = 1; i <= n; ++i) { scanf("%d", a + i); a[i + n] = a[i]; } int l = 0, r = 0; int L = 1, R = 1, ans = a[1], sum = 0; for(int i = 2; i <= n; ++i) if(a[i] > ans) ans = a[i], L = R = i; for(int i = 1; i <= n << 1; ++i) { sum += a[i]; while(l < r && deqv[r - 1] >= sum) --r; deq[r] = i; deqv[r] = sum; ++r; if(i > k) { if(i != deq[l]) { if(sum - deqv[l] > ans || sum - deqv[l] == ans && i - deq[l] < R - L + 1) { ans = sum - deqv[l]; L = deq[l] + 1; R = i; } } if(deq[l] == i - k) ++l; } } printf("%d %d %d\n", ans, (L - 1) % n + 1, (R - 1) % n + 1); } return 0; }
题意: 单点更新 环上区间RMQ
分析: 线段树模版题 - - 题目没说人走的方向啊 所以l>r是可以的
代码:
// // Created by TaoSama on 2015-09-21 // Copyright (c) 2015 TaoSama. All rights reserved. // //#pragma comment(linker, "/STACK:1024000000,1024000000") #include <algorithm> #include <cctype> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iomanip> #include <iostream> #include <map> #include <queue> #include <string> #include <set> #include <vector> using namespace std; #define pr(x) cout << #x << " = " << x << " " #define prln(x) cout << #x << " = " << x << endl const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7; int n, q; int maxv[N << 2]; #define root 1, n, 1 #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 void push_up(int rt) { maxv[rt] = max(maxv[rt << 1], maxv[rt << 1 | 1]); } void build(int l, int r, int rt) { if(l == r) { scanf("%d", &maxv[rt]); return; } int m = l + r >> 1; build(lson); build(rson); push_up(rt); } void update(int o, int v, int l, int r, int rt) { if(l == r) { maxv[rt] = v; return; } int m = l + r >> 1; if(o <= m) update(o, v, lson); else update(o, v, rson); push_up(rt); } int query(int L, int R, int l, int r, int rt) { if(L <= l && r <= R) { return maxv[rt]; } int m = l + r >> 1, ret = 0; if(L <= m) ret = max(ret, query(L, R, lson)); if(R > m) ret = max(ret, query(L, R, rson)); return ret; } int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); // freopen("out.txt","w",stdout); #endif ios_base::sync_with_stdio(0); while(scanf("%d", &n) == 1) { build(root); scanf("%d", &q); while(q--) { int op, x, y; scanf("%d%d%d", &op, &x, &y); if(op) { int ans = INF; if(x > y) swap(x, y); ans = min(ans, query(x, y, root)); ans = min(ans, max(query(1, x, root), query(y, n, root))); printf("%d\n", ans); } else update(x, y, root); } } return 0; }