LOJ刷题记录:2006-2011(SCOI2015)
2017-08-10 08:18
232 查看
LOJ刷题记录:2006-2011(SCOI2015)
loj#2006. 「SCOI2015」小凸玩矩阵
水题…二分答案之后用二分图匹配判断能不能取出k个比当前答案小的。
#include <bits/stdc++.h> using namespace std; const int MAXN = 505; struct node { int to, next, flow, neg; } edge[MAXN*MAXN]; int head[MAXN], top = 0; inline void push(int i, int j, int f) { ++top, edge[top] = (node) {j, head[i], f, top+1}, head[i] = top; ++top, edge[top] = (node) {i, head[j], 0, top-1}, head[j] = top; } const int S = MAXN-1, T = S-1; int lev[MAXN], vis[MAXN], bfstime = 0; int cur[MAXN]; queue<int> que; bool bfs() { vis[S] = ++bfstime, lev[S] = 0, que.push(S); while (!que.empty()) { int nd = que.front(); que.pop(); for (int i = head[nd]; i; i = edge[i].next) { int to = edge[i].to; if (vis[to] == bfstime || !edge[i].flow) continue; vis[to] = bfstime, lev[to] = lev[nd]+1, que.push(to); } } return vis[T] == bfstime; } int dfs(int nd, int flow) { if (nd == T || !flow) return flow; int ans = 0, t; for (int &i = cur[nd]; i; i = edge[i].next) { int to = edge[i].to; if (lev[to] != lev[nd]+1 || !edge[i].flow) continue; t = dfs(to, min(flow, edge[i].flow)); ans += t, flow -= t, edge[i].flow -= t, edge[edge[i].neg].flow += t; if (!flow) break; } return ans; } int dinic() { int ans = 0; while (bfs()) memcpy(cur, head, sizeof head), ans += dfs(S, INT_MAX); return ans; } int n, m, k; int a[255][255]; bool judge(int mid) { memset(head, 0, sizeof head); top = 0; for (int i = 1; i <= n; i++) push(S, i, 1); for (int i = 1; i <= m; i++) push(i+n, T, 1); for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) if (a[i][j] <= mid) push(i, n+j, 1); return dinic() >= k; } int main() { scanf("%d%d%d", &n, &m, &k); k = n-k+1; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) scanf("%d", &a[i][j]); int l = 0, r = 1e9, mid; while (l <= r) { mid = (l+r)>>1; if (judge(mid)) r = mid-1; else l = mid+1; } printf("%d\n", r+1); return 0; }
loj#2007. 「SCOI2015」国旗计划
细节神tm多……考虑贪心,对于每一个战士,我们显然要选取能接上他火炬且右端点尽可能靠后点..这样我们就可以连一条有向边,然后每个战士就要找他的后继中第一个使得覆盖总长超过m的…这显然可以用倍增维护。
这样只要维护last[nd][i]为包含nd在内向后2i个点,nxt[nd][i]表示不包含nd向后2i个点,sum[nd][i]表示包含nd向后2i的覆盖总长。之所以要记录last,nxt两个东西就是要去除中间重复的部分。
#include <bits/stdc++.h> using namespace std; const int MAXN = 200005; struct segment { int l, r, id; friend bool operator < (const segment &a, const segment &b) { return a.l < b.l; } } p[MAXN*2]; int n, m; int nxt[MAXN][20], last[MAXN][20]; long long sum[MAXN][20]; int dat[MAXN]; int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d%d", &p[i].l, &p[i].r), p[i].id = i; if (p[i].l > p[i].r) p[i].r += m; } sort(p+1, p+n+1); for (int i = 1; i <= n; i++) p[i+n] = (segment){p[i].l+m, p[i].r+m, i}; int pt = 1; for (int i = 1; i <= n; i++) { while (p[pt+1].l <= p[i].r) pt++; nxt[i][0] = pt<=n?pt:pt-n; sum[i][0] = p[i].r-p[i].l+1; last[i][0] = i; } for (int j = 1; j < 20; j++) for (register int i = 1; i <= n; i++) nxt[i][j] = nxt[nxt[i][j-1]][j-1], last[i][j] = nxt[last[i][j-1]][j-1]; for (int j = 1; j < 20; j++) for (register int i = 1; i <= n; i++) { int R1 = p[last[i][j-1]].r; int R2 = p[nxt[i][j-1]].l; if (R2 > m) R2 -= m; if (R1 > m) R1 -= m; if (R1 < R2) R1 += m; sum[i][j] = sum[i][j-1]+sum[nxt[i][j-1]][j-1]-(R1-R2+1); } for (int i = 1; i <= n; i++) { long long cur = 0; int pt = i, ans = 0; int last_pos = p[i].l-1; for (int j = 19; j >= 0; j--) { int pre = pt; if (sum[pt][j]+cur-(last_pos-p[pt].l+1) <= m) { cur += sum[pt][j]-(last_pos-p[pt].l+1), last_pos = p[last[pt][j]].r, pt = nxt[pt][j], ans |= 1<<j; if (last_pos > m) last_pos -= m; } } dat[p[i].id] = ans+1; } for (int i = 1; i <= n; i++) { printf("%d ", dat[i]); } puts(""); return 0; }
loj#2008. 「SCOI2015」小凸想跑步
半平面交还是非常好建的…算是第一个成功的板子吧..#include <bits/stdc++.h> using namespace std; const int MAXN = 200005; const double eps = 1e-8; struct point { double x, y; double ang; friend point operator + (const point &a, const point &b) { return (point){a.x+b.x, a.y+b.y}; } friend point operator - (const point &a, const point &b) { return (point){a.x-b.x, a.y-b.y}; } friend double operator * (const point &a, const point &b) { return a.x*b.y-a.y*b.x; } friend point operator * (double lambda, const point &a) { return (point){lambda*a.x, lambda*a.y}; } void display() { printf("(%.2f, %.2f) ", x, y); } }; typedef point vec; struct half_plane { point pt; vec v; friend bool operator < (const half_plane &a, const half_plane &b) { return a.v.ang < b.v.ang; } inline bool inside(point &p) { return v*(p-pt) >= eps; } friend point operator * (const half_plane &a, const half_plane &b) { double lambda = (a.pt*b.v-b.pt*b.v)/(b.v*a.v); return a.pt+lambda*a.v; } void display() { pt.display(); printf("+ k"); v.display(), printf("ang = %.2f\n", v.ang);} }; half_plane p[MAXN*2]; point q[MAXN*2]; int l, r; double HPC(vector<half_plane> &v) { sort(v.begin(), v.end()); l = 1, r = 0; for (auto i : v) { while (l < r && !i.inside(q[r])) r--; while (l < r && !i.inside(q[l+1])) l++; if (l > r || abs(i.v.ang-p[r].v.ang) >= eps) p[++r] = i, q[r] = i*p[r-1]; } while (l < r && !p[l].inside(q[r])) r--; q[r+1] = p[r]*p[l]; q[r+2] = q[l+1]; double ans = 0; if (r-l+1 >= 3) for (int i = l+1; i <= r+1; i++) ans += q[i]*q[i+1]; return ans/2; } int n; point pts[MAXN]; vector<half_plane> v; int main() { scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%lf%lf", &pts[i].x, &pts[i].y); double sig = 0; for (int i = 0; i < n; i++) sig += pts[i]*pts[(i+1)%n]; sig /= 2; for (int i = 0; i < n; i++) { vec ps = pts[(i+1)%n]-pts[i]; ps.ang = atan2(ps.y, ps.x); v.push_back((half_plane){pts[i], ps}); } for (int i = 1; i < n; i++) { point p1 = pts[i], p2 = pts[(i+1)%n], pt; double a = p1.y-p2.y-pts[0].y+pts[1].y, b = p2.x-p1.x-pts[1].x+pts[0].x; double c = p1*p2-pts[0]*pts[1]; if (abs(b) <= eps) { double xx = -c/a; pt = (point) {xx, 0}; } else { double xx = -c/b; pt = (point) {0, xx}; } v.push_back((half_plane){pt, (vec){b, -a, atan2(-a, b)}}); } double ans = HPC(v); printf("%.4f\n", ans/sig); return 0; }
loj#2009. 「SCOI2015」小凸玩密室
好神啊…用ui,j表示走完i的子树后走到i的深度为j的祖先的兄弟的最小代价;
用vi,j表示走完i的子树后走到i的深度为j的祖先的最小代价,用u算出v。
枚举起点,计算答案。
#include <bits/stdc++.h> using namespace std; const int MAXN = 200005; int n; long long a[MAXN], b[MAXN]; inline int lc(int nd) { return nd<<1; } inline int rc(int nd) { return nd<<1|1; } inline int fa(int nd) { return nd>>1; } inline long long L(int nd) { return b[(nd<<1)-1]; } inline long long R(int nd) { return b[nd<<1]; } long long f[MAXN][20], g[MAXN][20]; int depth[MAXN]; long long dis[MAXN]; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%lld", &a[i]); for (int i = 1; i < n; i++) scanf("%lld", &b[i]); depth[1] = 1, dis[1] = 0; for (int i = 2; i <= n; i++) depth[i] = depth[fa(i)]+1, dis[i] = dis[fa(i)]+b[i-1]; for (int i = n; i >= 1; i--) for (int j = depth[i], z = i; j > 1; j--, z = fa(z)) { int bro = (z&1)?z-1:z+1; if (lc(i)>n && rc(i)>n) f[i][j] = a[bro]*(dis[i]+dis[bro]-2*dis[fa(z)]); else if (rc(i)>n) f[i][j] = a[lc(i)]*L(i)+f[lc(i)][j]; else f[i][j] = min(a[lc(i)]*L(i)+f[lc(i)][depth[i]+1]+f[rc(i)][j], a[rc(i)]*R(i)+f[rc(i)][depth[i]+1]+f[lc(i)][j]); } for (int i = n; i >= 1; i--) for (int j = depth[i], z = i; j >= 0; j--, z = fa(z)) { if (lc(i)>n && rc(i)>n) g[i][j] = (dis[i]-dis[z])*a[z]; else if (rc(i)>n) g[i][j] = a[lc(i)]*L(i)+g[lc(i)][j]; else g[i][j] = min(a[lc(i)]*L(i)+f[lc(i)][depth[i]+1]+g[rc(i)][j], a[rc(i)]*R(i)+f[rc(i)][depth[i]+1]+g[lc(i)][j]); } long long ans = g[1][0]; //cerr << ans << endl; for (int i = 2; i <= n; i++) { long long cnt = g[i][depth[i]-1]; int nd = i, p = fa(nd), bro = (nd&1)?nd-1:nd+1; while (p) { if (rc(p)<=n) cnt += b[bro-1]*a[bro]+g[bro][depth[p]-1]; else cnt += b[p-1]*a[fa(p)]; nd = p, p = fa(nd), bro = (nd&1)?nd-1:nd+1; } //cerr << cnt << endl; ans = min(ans, cnt); } printf("%lld\n", ans); return 0; }
loj2010有点毒…先空着
loj#2011. 「SCOI2015」情报传递
离线处理,树上可持久化线段树即可…然而并跑不过两个log的树剖…#include <bits/stdc++.h> using namespace std; const int MAXN = 200005; int l[MAXN*20], r[MAXN*20], lc[MAXN*20], rc[MAXN*20], sum[MAXN*20], tp = 0, root[MAXN]; void build(int &nd, int opl, int opr) { nd = ++tp, l[nd] = opl, r[nd] = opr; if (opl < opr) build(lc[nd], opl, (opl+opr)>>1), build(rc[nd], ((opl+opr)>>1)+1, opr); } void modify(int pre, int &nd, int pos) { nd = ++tp, l[nd] = l[pre], r[nd] = r[pre], sum[nd] = sum[pre]+1; if (l[nd] < r[nd]) { int mid = (l[nd]+r[nd])>>1; if (pos <= mid) rc[nd] = rc[pre], modify(lc[pre], lc[nd], pos); else lc[nd] = lc[pre], modify(rc[pre], rc[nd], pos); } } int query(int nd, int opl, int opr) { if (opl > opr) return 0; if (l[nd] == opl && r[nd] == opr) return sum[nd]; else { int mid = (l[nd]+r[nd])>>1; if (opr <= mid) return query(lc[nd], opl, opr); else if (opl > mid) return query(rc[nd], opl, opr); else return query(lc[nd], opl, mid)+query(rc[nd], mid+1, opr); } } struct node { int to, next; } edge[MAXN]; int head[MAXN], top = 0; inline void push(int i, int j) { edge[++top] = (node) {j, head[i]}, head[i] = top; } int n, f[MAXN], rt, q; int a[MAXN], b[MAXN], c[MAXN], d[MAXN]; int T[MAXN], ans[MAXN]; int fa[MAXN], vis[MAXN], depth[MAXN]; int findf(int nd) { return fa[nd]?fa[nd]=findf(fa[nd]):nd; } vector<pair<int, int> > qy[MAXN]; void tarjan(int nd) { vis[nd] = 1, depth[nd] = depth[f[nd]]+1; for (vector<pair<int, int> >::iterator i = qy[nd].begin(); i != qy[nd].end(); ++i) if (vis[i->first]) ans[i->second] = findf(i->first); for (int i = head[nd]; i; i = edge[i].next) { int to = edge[i].to; if (to != f[nd]) tarjan(to); } fa[findf(nd)] = findf(f[nd]); } void dfs_build(int nd) { if (T[nd]) modify(root[f[nd]], root[nd], T[nd]); else root[nd] = root[f[nd]]; for (int i = head[nd]; i; i = edge[i].next) { int to = edge[i].to; if (to != f[nd]) dfs_build(to); } } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &f[i]); if (f[i]) push(f[i], i); else rt = i; } scanf("%d", &q); for (int i = 1; i <= q; i++) { scanf("%d", &a[i]); if (a[i] == 1) scanf("%d%d%d", &b[i], &c[i], &d[i]), qy[b[i]].push_back(make_pair(c[i], i)), qy[c[i]].push_back(make_pair(b[i], i)); else scanf("%d", &b[i]), T[b[i]] = i; } tarjan(rt); build(root[0], 1, n); dfs_build(rt); for (int i = 1; i <= q; i++) { if (a[i] == 2) continue; int lca = ans[i], min_pos = max(1, i-d[i]); int sig = query(root[b[i]], 1, min_pos-1)+query(root[c[i]], 1, min_pos-1)-query(root[lca], 1, min_pos-1)-query(root[f[lca]], 1, min_pos-1); printf("%d %d\n", depth[b[i]]+depth[c[i]]-depth[lca]*2+1, sig); } return 0; }
相关文章推荐
- HDU 水题 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016
- MSCRM 2011/2013/2015 修改显示记录数
- MSCRM 2011/2013/2015 修改显示记录数
- bzoj2333 [SCOI2011]棘手的操作
- 【LOJ】#2445. 「NOI2011」道路修建
- bzoj 4448: [Scoi2015]情报传递
- bzoj4448 [Scoi2015]情报传递
- 【块状链表】【SCOI2006】动态最值
- bzoj4448 [Scoi2015]情报传递(树链剖分+主席树)
- [HNOI2006]超级英雄Hero [Scoi2010]游戏 匈牙利算法 解题报告
- 【LOJ】#2111. 「JLOI2015」战争调度
- 【LOJ】#2117. 「HNOI2015」实验比较
- [SCOI2011] 糖果
- [bzoj2331][SCOI2011]地板
- 今天终于收到了我的MacBook Pro 13 2015 转载记录下如何在mac上配置jdk
- BZOJ1263 [SCOI2006]整数划分
- BZOJ 2331 [SCOI2011]地板 ——插头DP
- 网络流学习总结和省选专练SCOI2015小凸玩矩阵
- |BZOJ 2330|差分约束|[SCOI2011]糖果
- BZOJ4447: [Scoi2015]小凸解密码