HNOI2015解题报告
来源:互联网 发布:诸暨行知小学怎么样 编辑:程序博客网 时间:2024/05/20 23:57
HNOI2015解题报告
Author: Pengyihao
Day1 T1 亚瑟王
思路
用
注意这里的“机会”,是指有多少轮中,它前面的所有卡牌,要么在之前的轮中发动过,要么在这一轮中因为运气没有发动。
这里的“机会”不与自己有没有发动相关。所以就算在之前某轮中发动过,这一轮轮到它的时候贡献依然要增加。
于是有
代码
#include <bits/stdc++.h>typedef long long LL;#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)template <typename Tp> void in(Tp &x) { char ch = getchar(); x = 0; while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();}template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}const int MAXN = 230, MAXR = 140;int T, n, r, d[MAXN];double p[MAXN], f[MAXN][MAXR];double power(double x, int y){ double ret = 1; while (y) { if (y & 1) ret *= x; x *= x; y >>= 1; } return ret;}int main(){ freopen("arthur.in", "r", stdin); freopen("arthur.out", "w", stdout); in(T); while (T--) { in(n); in(r); FOR(i, 1, n) { scanf("%lf", &p[i]); in(d[i]); } memset(f, 0, sizeof f); f[1][r] = 1; FOR(i, 2, n) FOR(j, 1, r) { f[i][j] = 0; f[i][j] += f[i - 1][j + 1] * (1 - power(1 - p[i - 1], j + 1)); f[i][j] += f[i - 1][j] * power(1 - p[i - 1], j); } double ans = 0; FOR(i, 1, n) FOR(j, 1, r) { ans += f[i][j] * (1 - power(1 - p[i], j)) * d[i]; } printf("%.10lf\n", ans); } return 0;}
Day1 T2 接水果
思路
首先,我们求出每个点的dfs序。
然后对于一条x<–>y的路径,如果有路径包含它,那么有
如果
lca(x,y)=xory ,那么只需要这条路径的一个端点在深度大的点的子树中,另一个端点不在“深度小的点往深度大的点的方向上的第一个点”的子树中即可。否则,那么只需要这条路径的两个端点分别在
x 和y 的子树中即可。
我们令这条包含x<–>y的路径的两个端点中dfs序小的点为
对于上面两种情况中的任意一种情况,这种情况中
于是我们就把问题转化为了,每个盘子对应一对(或两对,因为有“不在子树”)区间,然后对于每个水果的两个点,两个区间分别包含其两个点的盘子中,权值第
我们可以把一维转化成
于是可以用扫描线+树状数组套主席树解决。
代码
#include <bits/stdc++.h>using std::map;typedef long long LL;#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)#define debug(...) fprintf(stderr, __VA_ARGS__)template <typename Tp> void in(Tp &x) { char ch = getchar(); x = 0; while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();}template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}const int MAXN = 100010;const int appear = 0, disappear = 2, query = 1;int n, p, q, ev_tot;int cnt, head[MAXN], data[MAXN << 1], nxt[MAXN << 1];int INDEX, dfn[MAXN], ed[MAXN], depth[MAXN];int anc[MAXN][18];int ans[MAXN];map<int, int>M; int M_point, to[MAXN << 3];struct Event { int type, num; int time, l, r, w;} ev[MAXN << 3];namespace segment_tree{ const int MAXS = MAXN * 250; int seg_tot = 0, rot[MAXN], sz[MAXS], ch[MAXS][2]; int should_remove[250], should_add[250]; void build(int &now, int l, int r) { now = ++seg_tot; if (l == r) return; int mid = (l + r) >> 1; build(ch[now][0], l, mid); build(ch[now][1], mid + 1, r); } void initialize() { build(rot[0], 1, M_point); FOR(i, 1, n) rot[i] = rot[0]; } void push(int &now, int l, int r, int x, int modi) { int tmp = now; now = ++seg_tot; sz[now] = sz[tmp]; ch[now][0] = ch[tmp][0]; ch[now][1] = ch[tmp][1]; sz[now] += modi; if (l == r) return; int mid = (l + r) >> 1; if (x <= mid) push(ch[now][0], l, mid, x, modi); else push(ch[now][1], mid + 1, r, x, modi); } void getdown(int &ret, bool t) { ret = 0; FOR(i, 1, should_add[0]) ret += sz[ch[should_add[i]][t]]; FOR(i, 1, should_remove[0]) ret -= sz[ch[should_remove[i]][t]]; } void godown(bool t) { FOR(i, 1, should_add[0]) should_add[i] = ch[should_add[i]][t]; FOR(i, 1, should_remove[0]) should_remove[i] = ch[should_remove[i]][t]; } void _query(int w, int l, int r, int num) { if (l == r) { ans[num] = l; return; } int ldata; getdown(ldata, 0); int mid = (l + r) >> 1; if (ldata >= w) {godown(0); _query(w, l, mid, num);} else {godown(1); _query(w - ldata, mid + 1, r, num);} } void insert(int l, int r, int w) { if (l > r) { debug("WA"); } //This line is for gdb while (l <= n) { push(rot[l], 1, M_point, w, 1); l += l & -l; } r++; while (r <= n) { push(rot[r], 1, M_point, w, -1); r += r & -r; } } void remove(int l, int r, int w) { while (l <= n) { push(rot[l], 1, M_point, w, -1); l += l & -l; } r++; while (r <= n) { push(rot[r], 1, M_point, w, 1); r += r & -r; } } void query(int l, int r, int w, int num) { l--; should_remove[0] = should_add[0] = 0; while (l) { should_remove[++should_remove[0]] = rot[l]; l -= l & -l; } while (r) { should_add[++should_add[0]] = rot[r]; r -= r & -r; } _query(w, 1, M_point, num); }}int lca(int x, int y){ if (depth[x] < depth[y]) x ^= y ^= x ^= y; if (depth[x] != depth[y]) { int delta = depth[x] - depth[y]; DNF(i, 17, 0) if (delta >> i & 1) x = anc[x][i]; } if (x == y) return x; DNF(i, 17, 0) if (anc[x][i] && anc[y][i] && anc[x][i] != anc[y][i]) { x = anc[x][i]; y = anc[y][i]; } return anc[x][0];}void work(int now){ if (ev[now].type == appear) { segment_tree::insert(ev[now].l, ev[now].r, ev[now].w); } else if (ev[now].type == disappear) { segment_tree::remove(ev[now].l, ev[now].r, ev[now].w); } else { segment_tree::query(1, ev[now].l, ev[now].w, ev[now].num); }}bool cmp(const Event &a, const Event &b){ return a.time < b.time || a.time == b.time && a.type < b.type;}bool cmp2(const Event &a, const Event &b){ return a.w < b.w;}void add(int x, int y){ nxt[cnt] = head[x]; data[cnt] = y; head[x] = cnt++; nxt[cnt] = head[y]; data[cnt] = x; head[y] = cnt++;}void dfs(int now, int pa){ depth[now] = depth[pa] + 1; anc[now][0] = pa; for (int i = 1; anc[now][i - 1]; i++) anc[now][i] = anc[anc[now][i - 1]][i - 1]; dfn[now] = ++INDEX; for (int i = head[now]; i != -1; i = nxt[i]) { if (data[i] != pa) dfs(data[i], now); } ed[now] = INDEX;}int find_fa(int now, int depth){ FOR(i, 0, 17) if (depth >> i & 1) now = anc[now][i]; return now;}int main(){ freopen("fruit.in", "r", stdin); freopen("fruit.out", "w", stdout); memset(head, -1, sizeof head); in(n); in(p); in(q); FOR(i, 1, n - 1) { int u, v; in(u); in(v); add(u, v); } dfs(1, 0); FOR(i, 1, p) { int u, v, w; in(u); in(v); in(w); int anc = lca(u, v); if (dfn[u] > dfn[v]) u ^= v ^= u ^= v; if (u == anc) { int nodes = find_fa(v, depth[v] - depth[u] - 1); int ss = dfn[nodes], tt = ed[nodes]; if (ss != 1) { ev[++ev_tot].time = 1; ev[ev_tot].l = dfn[v]; ev[ev_tot].r = ed[v]; ev[ev_tot].type = appear; ev[ev_tot].w = w; ev[++ev_tot].time = ss - 1; ev[ev_tot].l = dfn[v]; ev[ev_tot].r = ed[v]; ev[ev_tot].type = disappear; ev[ev_tot].w = w; } if (tt != n) { ev[++ev_tot].time = dfn[v]; ev[ev_tot].l = tt + 1; ev[ev_tot].r = n; ev[ev_tot].type = appear; ev[ev_tot].w = w; ev[++ev_tot].time = ed[v]; ev[ev_tot].l = tt + 1; ev[ev_tot].r = n; ev[ev_tot].type = disappear; ev[ev_tot].w = w; } } else { ev[++ev_tot].time = dfn[u]; ev[ev_tot].l = dfn[v]; ev[ev_tot].r = ed[v]; ev[ev_tot].type = appear; ev[ev_tot].w = w; ev[++ev_tot].time = ed[u]; ev[ev_tot].l = dfn[v]; ev[ev_tot].r = ed[v]; ev[ev_tot].type = disappear; ev[ev_tot].w = w; } } std::sort(ev + 1, ev + ev_tot + 1, cmp2); FOR(i, 1, ev_tot) { if (i != 1 && ev[i].w == ev[i - 1].w) continue; M[ev[i].w] = ++M_point; to[M_point] = ev[i].w; } FOR(i, 1, ev_tot) { ev[i].w = M[ev[i].w]; } FOR(i, 1, q) { int u, v, w; in(u); in(v); in(w); if (dfn[u] > dfn[v]) u ^= v ^= u ^= v; ev[++ev_tot].time = dfn[u]; ev[ev_tot].l = dfn[v]; ev[ev_tot].w = w; ev[ev_tot].num = i; ev[ev_tot].type = query; } std::sort(ev + 1, ev + ev_tot + 1, cmp); segment_tree::initialize(); FOR(i, 1, ev_tot) work(i); FOR(i, 1, q) printf("%d\n", to[ans[i]]); return 0;}
Day1 T3 菜肴制作
思路
按照逆序拓扑排序,然后构造字典序最大的解。
代码
#include <bits/stdc++.h>using std::priority_queue;typedef long long LL;#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)template <typename Tp> void in(Tp &x) { char ch = getchar(); x = 0; while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();}template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}const int MAXN = 100010;int T, n, m, chose, du[MAXN], order[MAXN];int cnt, head[MAXN], data[MAXN << 1], nxt[MAXN << 1];priority_queue<int>q;void add(int x, int y){ nxt[cnt] = head[x]; data[cnt] = y; head[x] = cnt++; nxt[cnt] = head[y]; data[cnt] = x; head[y] = cnt++;}int main(){ freopen("dishes.in", "r", stdin); freopen("dishes.out", "w", stdout); in(T); while (T--) { memset(du, 0, sizeof du); memset(head, -1, sizeof head); cnt = 0; in(n); in(m); chose = n; FOR(i, 1, m) { int x, y; in(x); in(y); add(y, x); du[x]++; } FOR(i, 1, n) { if (!du[i]) q.push(i); } order[0] = 0; while (!q.empty()) { int now = q.top(); q.pop(); chose--; order[++order[0]] = now; for (int i = head[now]; i != -1; i = nxt[i]) { du[data[i]]--; if (!du[data[i]]) { q.push(data[i]); } } } if (chose) puts("Impossible!"); else { DNF(i, n, 1) printf("%d ", order[i]); putchar(10); } } return 0;}
Day2 T1 落忆枫音
思路
考虑没有环的情况。
每个点(除了
所有方案数为
但是有环,所以答案要减去它。
设
这个可以dp……
令
则
代码
#include <bits/stdc++.h>using std::queue;typedef long long LL;#define FOR(i, a, b) for (LL i = (a), i##_END_ = (b); i <= i##_END_; i++)#define DNF(i, a, b) for (LL i = (a), i##_END_ = (b); i >= i##_END_; i--)template <typename Tp> void in(Tp &x) { char ch = getchar(); x = 0; while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();}template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}const LL MOD = 1000000007;const LL MAXN = 200010;LL n, m, x, y, ans = 1;LL f[MAXN], du[MAXN], rdu[MAXN];LL head[MAXN], data[MAXN], nxt[MAXN], cnt;LL head1[MAXN], data1[MAXN], nxt1[MAXN], cnt1;queue<LL>q;void add(LL x, LL y){ nxt[cnt] = head[x]; data[cnt] = y; head[x] = cnt++;}void add2(LL x, LL y){ nxt1[cnt1] = head1[x]; data1[cnt1] = y; head1[x] = cnt1++;}LL power(LL x, LL y){ LL ret = 1; while (y) { if (y & 1) ret = 1ll * ret * x % MOD; x = 1ll * x * x % MOD; y >>= 1; } return ret;}int main(){ freopen("maple.in", "r", stdin); freopen("maple.out", "w", stdout); memset(head, -1, sizeof head); memset(head1, -1, sizeof head1); in(n); in(m); in(x); in(y); FOR(i, 1, m) { LL u, v; in(u); in(v); add(u, v); add2(v, u); du[v]++; rdu[v]++; } FOR(i, 2, n) if (i != y) ans = 1ll * ans * du[i] % MOD; if (x == y || y == 1) { if (y != 1) ans = 1ll * ans * du[x] % MOD; printf("%lld\n", ans); return 0; } LL tmp = ans; ans = 1ll * ans * (du[y] + 1) % MOD; FOR(i, 1, n) { if (!du[i]) q.push(i); } while (!q.empty()) { LL now = q.front(); q.pop(); if (now == y) { f[now] = tmp; } else { f[now] = 0; for (LL i = head1[now]; i != -1; i = nxt1[i]) { f[now] = (f[now] + f[data1[i]]) % MOD; } f[now] = 1ll * f[now] * power(rdu[now], MOD - 2) % MOD; } for (LL i = head[now]; i != -1; i = nxt[i]) { du[data[i]]--; if (!du[data[i]]) { q.push(data[i]); } } } printf("%lld\n", (ans - f[x] + MOD) % MOD); return 0;}
Day2 T2
这是一道动态点分治的题目。但因为我还没有搞这个专题所以暂且跳过。
Day2 T3
思路
这个题目还是很容易的。
因为所有的
那么构成的就是一座森林(把相等的点用并差集缩起来)。
然后就可以树形dp辣!
因为有等于,所以我们不知道每棵子树中有多少“块”元素。
我们把相等的元素看成一块,那么一棵子树就是若干个块的大小关系。
我们设第
则两棵子树合并的结果
代码
#include <bits/stdc++.h>typedef long long LL;#define FOR(i, a, b) for (int i = (a), i##_END_ = (b); i <= i##_END_; i++)#define DNF(i, a, b) for (int i = (a), i##_END_ = (b); i >= i##_END_; i--)template <typename Tp> void in(Tp &x) { char ch = getchar(); x = 0; while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();}template <typename Tp> Tp Min(Tp x, Tp y) {return x < y ? x : y;}template <typename Tp> Tp Max(Tp x, Tp y) {return x > y ? x : y;}template <typename Tp> Tp chkmax(Tp &x, Tp y) {return x > y ? x : x=y;}template <typename Tp> Tp chkmin(Tp &x, Tp y) {return x < y ? x : x=y;}const int MAXN = 110;const int MOD = 1000000007;struct Edge { int l, r;} edge[MAXN];int edge_lenth;int n, m;char compare[10];int du[MAXN], f[MAXN][MAXN];int head[MAXN], nxt[MAXN], data[MAXN], cnt;int fa[MAXN];int find(int x){ int tmp = x, pre; while (tmp != fa[tmp]) tmp = fa[tmp]; while (x != tmp) { pre = fa[x]; fa[x] = tmp; x = pre; } return tmp;}void merge(int x, int y){ int fx = find(x), fy = find(y); if (fx != fy) fa[fx] = fy;}int g[MAXN], jie[MAXN], ni[MAXN];int C(int x, int y){ if (!y) return 1; if (x < y) return 0; return 1ll * jie[x] * ni[y] % MOD * ni[x - y] % MOD;}void dfs(int now){ for (int i = head[now]; i != -1; i = nxt[i]) dfs(data[i]); memset(g, 0, sizeof g); if (head[now] != -1) FOR(k, 1, n) g[k] = f[data[head[now]]][k]; if (head[now] != -1) for (int i = nxt[head[now]]; i != -1; i = nxt[i]) { memset(f[now], 0, sizeof f[now]); FOR(k, 1, n) FOR(l, 1, n) FOR(j, Max(k, l), Min(n, k + l)) { f[now][j] = ( f[now][j] + 1ll * g[k] % MOD * f[data[i]][l] % MOD * C(j, k) % MOD * C(k, k + l - j) % MOD ) % MOD; } FOR(k, 1, n) g[k] = f[now][k]; } if (head[now] == -1) f[now][1] = 1; else FOR(i, 1, n) f[now][i] = g[i - 1];}int power(int x, int y){ int ret = 1; while (y) { if (y & 1) ret = 1ll * ret * x % MOD; x = 1ll * x * x % MOD; y >>= 1; } return ret;}void add(int x, int y){ nxt[cnt] = head[x]; data[cnt] = y; head[x] = cnt++;}int main(){ freopen("pairwise.in", "r", stdin); freopen("pairwise.out", "w", stdout); memset(head, -1, sizeof head); jie[0] = 1; FOR(i, 1, 100) jie[i] = 1ll * jie[i - 1] * i % MOD; ni[100] = power(jie[100], MOD - 2); DNF(i, 99, 1) ni[i] = 1ll * ni[i + 1] * (i + 1) % MOD; ni[0] = 1; in(n); in(m); FOR(i, 1, n) fa[i] = i; FOR(i, 1, m) { int x, y; in(x); scanf("%s", compare); in(y); if (compare[0] == '<') { edge[++edge_lenth].l = x; edge[edge_lenth].r = y; } else merge(x, y); } int ans = 0; FOR(i, 1, edge_lenth) { int fx = find(edge[i].l); int fy = find(edge[i].r); if (fx == fy) { puts("0"); return 0; } add(fx, fy); du[fy]++; } int rot = 0; FOR(i, 1, n) { if (!du[find(i)]) rot = find(i); } if (!rot) { puts("0"); return 0; } dfs(rot); FOR(i, 1, n) ans = (ans + f[rot][i]) % MOD; printf("%d\n", ans); return 0;}
- HNOI2015解题报告
- BZOJ4008: [HNOI2015]亚瑟王 解题报告
- BZOJ4009: [HNOI2015]接水果 解题报告
- BZOJ4010: [HNOI2015]菜肴制作 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- 解题报告
- Antiprime解题报告
- expr解题报告
- 华容道解题报告
- tju解题报告
- zju1062/pku1095解题报告
- UsacoGate解题报告 --- 序曲
- ZJU 2060 解题报告
- Unity3d
- HNOI2012解题报告
- 大日志文件中如何统计单词个数?及map按value排序lambda表达式版
- HNOI2014解题报告
- PHP日期和时间设置时区
- HNOI2015解题报告
- 51Nod-1574-排列转换
- ubuntu+vim+opencv+cmake环境搭建
- MATLAB学习笔记
- HNOI2017总结
- 抽象类和接口的相同点和不同点,学习笔记
- 『ORACLE』 约束实验(11g)
- Linux学习笔记--常用知识
- C++编译OpenCV生成动态库问题解决