[比赛][Zjoi2017 Day1]
2017-03-28 20:58
246 查看
[比赛][Zjoi2017 Day1]
ZJOI2017 DAY1
为什么第一题就是仙人掌啊吓死人了。。。刚看完题发现只会打10分的暴力,然后看了第二题发现还是只会打10分的暴力,然后看了第三题还是只会十分的暴力。。。
感觉要30分滚粗了。。。
先写好了第一题的暴力,调了一会(其实调了一个多小时)过了样例以后发现n哪怕再大1都跑不过。。。于是就跑了一下链的情况,发现答案就是2n−2,好开心啊
又想了一会树的情况,发现树的情况就是问把一棵树拆成很多条链(链的头尾相连可以连成仙人掌),问又多少种情况,然后大力DP一下,但是转移的时候要乘个系数并不会,瞎JB乱乘了一个当然是错的。
打完还有半个小时多一点,把二三两题的暴力打完就滚粗了。。。。
然后来讲一下一二两题的做法。
仙人掌
可以看一下这篇题解:http://blog.csdn.net/akak__ii/article/details/65935711代码:
#include <bits/stdc++.h> using namespace std; const int Maxn = 500010; const int Mod = 998244353; typedef long long ll; inline char get(void) { static char buf[100000], *p1 = buf, *p2 = buf; if (p1 == p2) { p2 = (p1 = buf) + fread(buf, 1, 100000, stdin); if (p1 == p2) return EOF; } return *p1++; } inline void read(int &x) { x = 0; static char c; for (; !(c >= '0' && c <= '9'); c = get()); for (; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = get()); } ll f[Maxn]; int head[Maxn], sub, d[Maxn], dfn[Maxn], cnt, fa[Maxn], rev[Maxn]; struct Edge { int to, nxt; Edge (void) {} Edge (const int &to, const int &nxt) : to(to), nxt(nxt) {} } edge[1000010]; inline void add(int a, int b) { edge[++sub] = Edge(b, head[a]), head[a] = sub; } inline bool dfs(int u) { dfn[u] = ++cnt; for (int i = head[u], v; i; i = edge[i].nxt) { v = edge[i].to; if (!dfn[v]) { fa[v] = u; if (dfs(v)) return 1; } else if (dfn[v] > dfn[u]) for (d[u] -= 2; v != u; rev[v] = 1, d[v] -= 2, v = fa[v]) if (rev[v]) return 1; } return 0; } int T, n, m; int main(void) { //freopen("in.txt", "r", stdin); register int i; int a, b; for (f[0] = f[1] = 1, i = 2; i < Maxn; i++) f[i] = (f[i - 2] * (i - 1) % Mod + f[i - 1]) % Mod; read(T); while (T--) { read(n); read(m); sub = cnt = 0; for (int i = 1; i <= n; i++) head[i] = d[i] = dfn[i] = rev[i] = 0; for (int i = 1; i <= m; i++) { read(a), read(b); d[a]++, d++; add(a, b), add(b, a); } if (dfs(1)) { puts("0"); continue; } ll ans = 1; for (int i = 1; i <= n; i++) ans = (ans * f[d[i]]) % Mod; printf("%lld\n", ans); } return 0; }
[b]树状数组
可以发现劼司机打错的树状数组求的是后缀和。回答错误当且仅当 x-1 的修改次数模 2 意义下不等于 y 的修改次数(即和为奇数)。所以把询问看作点 (x-1, y),我们用树套树来维护这个平面。
对于修改操作 (x, y),它会对三种询问点产生影响:若询问点只包含 x 或只包含 y,那么有 1/(y-x+1) 的几率反色;若两个都包含,则 2/(y-x+1) 的几率反色。
若当前为 0 的概率是 x,然后有 p 的几率反色,则 x 变成 x*(1-p)+(1-x)*p。此式也适用于标记合并。
然后学习了一下如何在区间上打永久标记
代码:
#include <bits/stdc++.h> using namespace std; const int Maxn = 400010; const int Maxm = 40000000; const int Mod = 998244353; typedef long long ll; inline char get(void) { static char buf[100000], *p1 = buf, *p2 = buf; if (p1 == p2) { p2 = (p1 = buf) + fread(buf, 1, 100000, stdin); if (p1 == p2) return EOF; } return *p1++; } inline void read(int &x) { x = 0; static char c; for (; !(c >= '0' && c <= '9'); c = get()); for (; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = get()); } inline void write(int x) { if (!x) return (void) (puts("0")); static short st[12], top; while (x) st[++top] = x % 10, x /= 10; while (top) putchar('0' + st[top--]); putchar('\n'); } int Pow(ll a, int n) { ll ans = 1; while (n) { if (n & 1) ans = (ans * a) % Mod; a = (a * a) % Mod; n >>= 1; } return ans; } inline int merge(int a, int b) { return (1LL * a * (Mod + 1 - b) % Mod + 1LL * b * (Mod + 1 - a) % Mod) % Mod; } int t2[Maxm], sz, ls[Maxm], rs[Maxm], rt[Maxn], n, m; inline void add2(int &o, int l, int r, int L, int R, int v) { if (!o) o = ++sz; if (L == l && R == r) { t2[o] = merge(t2[o], v); return ; } int mid = (l + r) >> 1; if (mid >= R) add2(ls[o], l, mid, L, R, v); else if (mid < L) add2(rs[o], mid + 1, r, L, R, v); else add2(ls[o], l, mid, L, mid, v), add2(rs[o], mid + 1, r, mid + 1, R, v); } inline void add1(int o, int l, int r, int L, int R, int L1, int R1, int v) { if (l == L && r == R) { add2(rt[o], 0, n, L1, R1, v); return ; } int mid = (l + r) >> 1; if (mid >= R) add1(o << 1, l, mid, L, R, L1, R1, v); else if (mid < L) add1(o << 1 | 1, mid + 1, r, L, R, L1, R1, v); else add1(o << 1, l, mid, L, mid, L1, R1, v), add1(o << 1 | 1, mid + 1, r, mid + 1, R, L1, R1, v); } inline int query2(int o, int l, int r, int p) { if (!o) return 0; int ret = t2[o]; if (l == r) return ret; int mid = (l + r) >> 1; if (p <= mid) return merge(query2(ls[o], l, mid, p), ret); else return merge(query2(rs[o], mid + 1, r, p), ret); } inline int query1(int o, int l, int r, int p1, int p2) { int ret = query2(rt[o], 0, n, p2); if (l == r) { return ret; } int mid = (l + r) >> 1; if (p1 <= mid) return merge(query1(o << 1, l, mid, p1, p2), ret); else return merge(query1(o << 1 | 1, mid + 1, r, p1, p2), ret); } int main(void) { //freopen("in.txt", "r", stdin); read(n), read(m); n++; int op, l, r, inv, tot, len; for (int i = 1; i <= m; i++) { read(op), read(l), read(r); len = r - l + 1, inv = Pow(len, Mod - 2); if (op == 1) { add1(1, 0, n, l, r, l, r, 2LL * inv % Mod); add1(1, 0, n, 0, l - 1, l, r, inv); add1(1, 0, n, l, r, r + 1, n, inv); tot++; } else { if (l == 1 && (tot & 1)) write(query1(1, 0, n, 0, r)); else write((Mod + 1 - query1(1, 0, n, l - 1, r)) % Mod); } } return 0; }
ZJOI2018加油咯
或者二试翻盘
相关文章推荐
- 【游记】ZJOI2017 Day1 #1
- 【游记】ZJOI2017 Day1 #3
- 【游记】ZJOI2017 Day1 #2
- [TravelNotes] ZJOI 2017 DAY1 滚粗记
- bzoj4785 UOJ #291 ZJOI2017 Day1 树状数组
- [比赛][ZJOI2011 day1]
- 【省选专题一】图论 jzoj 5060.【GDOI2017第二轮模拟day1】公路建设 线段树+最小生成树+并查集
- ZJOI2017 NGU!
- 「6月雅礼集训 2017 Day1」说无可说
- [ZJOI2017]树状数组
- LOJ 6100 「2017 山东二轮集训 Day1」第一题
- 「长乐集训 2017 Day1」区间 线段树
- 比赛组队(百度2017秋招真题)
- 【JZOJ5061】【GDOI2017第二轮模拟day1】最长路径
- noip2017 Day1 T3 逛公园
- 2017 陕西省网络安全技术比赛 Writeup
- ●洛谷P3687 [ZJOI2017]仙人掌
- [NOIp2017 Day1 T2] 时间复杂度complexity(栈,模拟)
- 2017北京国庆刷题Day1 afternoon
- 2017国庆郑州集训Day1