A - 风之国
题意: 给出X轴上N个点的坐标 X轴上的点按大小两两互相连通 现在要必须干掉K条路 求最小花费分析: 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;
}
B - 真正的AC自动机
题意: 每个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;
}
C - 最大的矩形
题意: 求连续的最大矩形
分析: 单调栈或者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;
}
D - 爱探险的小Z
题意: 长度为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;
}
E - 爱爬山的小Z
题意: 单点更新 环上区间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;
}