首页 > 代码库 > Hnoi2017试题泛做
Hnoi2017试题泛做
Day1
4825: [Hnoi2017]单旋
注意到二叉查找树的一个性质:其中序遍历就是所有元素按权值排序的顺序。
所以我们可以离线地把这棵树的中序遍历求出来。然后我们在插入的时候就可以用一个set来维护前驱后继,这样就可以维护出整棵树的形态。
接着我们发现将最大、最小单旋到根后,一定会有一边儿子是空的,并且剩下的子树的深度+1。于是我们就只要支持单点修改、区间加、单点查询的数据结构即可。树状数组就好了。
然后树的形态维护的时候大力判断一下就好啦。
1 #include <cstdio> 2 #include <cmath> 3 #include <set> 4 #include <algorithm> 5 6 #define R register 7 #define P std::pair<int, int> 8 #define mkp std::make_pair 9 #define maxn 100010 10 #define fir first 11 #define sec second 12 int v[maxn], ch[maxn][2], fa[maxn], tot; 13 std::set<P> s; 14 int q[maxn]; 15 int dfn[maxn], inv[maxn], timer, pos[maxn], ltag; 16 int ql, qr; 17 int hash[maxn]; 18 int bt[maxn]; 19 void add(R int x, R int val) {for (; x <= tot; x += x & -x) bt[x] += val;} 20 int query(R int x) {R int ret = 0; for (; x; x -= x & -x) ret += bt[x]; return ret;} 21 void modify(R int l, R int r, R int v) 22 { 23 // printf("l = %d r = %d v = %d\n", l, r, v); 24 add(l, v); add(r + 1, -v); 25 } 26 int main() 27 { 28 R int n, root; scanf("%d", &n); 29 s.insert(mkp(0, 0)); 30 s.insert(mkp(1e9 + 7, 0)); 31 for (R int i = 1; i <= n; ++i) 32 { 33 R int opt; scanf("%d", &opt); q[i] = opt; 34 if (opt == 1) {R int key; scanf("%d", &key); v[++tot] = key; hash[tot] = key;} 35 } 36 std::sort(hash + 1, hash + tot + 1); 37 for (R int i = 1; i <= n; ++i) dfn[i] = std::lower_bound(hash + 1, hash + tot + 1, v[i]) - hash; 38 for (R int i = 1, nw = 0; i <= n; ++i) 39 { 40 R int opt = q[i]; 41 if (opt == 1) 42 { 43 R P now = mkp(v[++nw], nw); 44 R P prev = *(--s.upper_bound(now)), next = *s.upper_bound(now); 45 s.insert(now); 46 if (prev.sec && !ch[prev.sec][1]) 47 { 48 ch[prev.sec][1] = nw; 49 fa[nw] = prev.sec; 50 } 51 else if (next.sec && !ch[next.sec][0]) 52 { 53 ch[next.sec][0] = nw; 54 fa[nw] = next.sec; 55 } 56 !fa[nw] ? root = nw : 0; 57 58 R int dep; 59 printf("%d\n", dep = fa[nw] ? query(dfn[fa[nw]]) + 1 : 1); 60 modify(dfn[nw], dfn[nw], dep - query(dfn[nw])); 61 } 62 else if (opt == 2) 63 { 64 R P xmin = *(++s.begin()); R int xc = xmin.sec; 65 printf("%d\n", query(dfn[xc])); 66 // printf("fa %d\n", fa[xc]); 67 modify(!fa[xc] ? tot + 1 : dfn[fa[xc]], tot, 1); 68 modify(dfn[xc], dfn[xc], 1 - query(dfn[xc])); 69 70 if (root != xc) 71 { 72 ch[fa[xc]][0] = ch[xc][1]; 73 fa[ch[xc][1]] = fa[xc]; 74 fa[root] = xc; 75 ch[xc][1] = root; 76 root = xc; 77 fa[xc] = 0; 78 } 79 } 80 else if (opt == 3) 81 { 82 R P xmax = *(++s.rbegin()); R int xc = xmax.sec; 83 printf("%d\n", query(dfn[xc])); 84 modify(1, !fa[xc] ? 0 : dfn[fa[xc]], 1); 85 modify(dfn[xc], dfn[xc], 1 - query(dfn[xc])); 86 87 if (root != xc) 88 { 89 ch[fa[xc]][1] = ch[xc][0]; 90 fa[ch[xc][0]] = fa[xc]; 91 fa[root] = xc; 92 ch[xc][0] = root; 93 root = xc; 94 fa[xc] = 0; 95 } 96 } 97 else if (opt == 4) 98 { 99 R P xmin = *(++s.begin()); R int xc = xmin.sec;100 printf("%d\n", query(dfn[xc]));101 modify(dfn[xc] + 1 , !fa[xc] ? tot : dfn[fa[xc]] - 1, -1);102 103 xc == root ? fa[root = ch[xc][1]] = 0 :104 (ch[fa[xc]][0] = ch[xc][1],105 fa[ch[xc][1]] = fa[xc]);106 s.erase(xmin);107 }108 else109 {110 R P xmax = *(++s.rbegin()); R int xc = xmax.sec;111 // printf("max %d %d\n", xc, fa[xc]);112 printf("%d\n", query(dfn[xc]));113 modify(!fa[xc] ? 1 : dfn[fa[xc]] + 1, dfn[xc] - 1, -1);114 115 xc == root ? fa[root = ch[xc][0]] = 0 :116 (ch[fa[xc]][1] = ch[xc][0],117 fa[ch[xc][0]] = fa[xc]);118 s.erase(xmax);119 }120 }121 return 0;122 }123 /*124 6125 1 1126 1 2127 1 4128 4129 2130 5131 性质:二叉查找树的子树的权值对应的是一个区间。并且有且仅有所有子树内的点在这个区间内。132 */
4826: [Hnoi2017]影魔
第1种的贡献可以用单调栈算。第2种的贡献没那么好算,所以我们来考虑1+2的贡献。1+2的贡献可以转为二维偏序,用排序+线段树来搞。
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 5 #define R register 6 #define maxn 200010 7 #define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b)) 8 inline int F() 9 { 10 R char ch; R int cnt; 11 while (ch = getchar(), ch < ‘0‘ || ch > ‘9‘) ; 12 cnt = ch - ‘0‘; 13 while (ch = getchar(), ch >= ‘0‘ && ch <= ‘9‘) cnt = cnt * 10 + ch - ‘0‘; 14 return cnt; 15 } 16 typedef long long ll; 17 struct Query { 18 int l, r; 19 } q[maxn]; 20 struct Chain { 21 Chain *next; 22 int id; 23 } *last[maxn], mem[maxn], *tot = mem; 24 struct Opt { 25 int x, id, type; 26 inline bool operator < (const Opt &that) const {return x < that.x;} 27 } op[maxn << 1]; 28 int ans1[maxn]; ll ans2[maxn]; 29 int st[maxn], top, a[maxn]; 30 int ql, qr; 31 ll tr[maxn << 2], tag[maxn << 2]; 32 inline void pushdown(R int o, R int l, R int r, R int mid) 33 { 34 if (tag[o]) 35 { 36 tag[o << 1] += tag[o]; 37 tag[o << 1 | 1] += tag[o]; 38 tr[o << 1] += 1ll * tag[o] * (mid - l + 1); 39 tr[o << 1 | 1] += 1ll * tag[o] * (r - mid); 40 tag[o] = 0; 41 } 42 } 43 inline void update(R int o) {tr[o] = tr[o << 1] + tr[o << 1 | 1];} 44 void modify(R int o, R int l, R int r) 45 { 46 if (ql <= l && r <= qr) 47 { 48 ++tag[o]; tr[o] += (r - l + 1); 49 return ; 50 } 51 R int mid = l + r >> 1; 52 pushdown(o, l, r, mid); 53 if (ql <= mid) modify(o << 1, l, mid); 54 if (mid < qr) modify(o << 1 | 1, mid + 1, r); 55 update(o); 56 } 57 ll query(R int o, R int l, R int r) 58 { 59 if (ql <= l && r <= qr) return tr[o]; 60 R int mid = l + r >> 1; 61 R ll ret = 0; 62 pushdown(o, l, r, mid); 63 if (ql <= mid) ret += query(o << 1, l, mid); 64 if (mid < qr) ret += query(o << 1 | 1, mid + 1, r); 65 return ret; 66 } 67 int bt[maxn], n, lef[maxn], rig[maxn], r[maxn], Fa[maxn]; 68 int Find(R int x) {return Fa[x] == x ? x : Fa[x] = Find(Fa[x]);} 69 inline void add(R int x) {for (; x <= n; x += x & -x) ++bt[x];} 70 inline int query(R int x) {R int ret = 0; for (; x; x -= x & -x) ret += bt[x]; return ret;} 71 int main() 72 { 73 n = F(); R int m = F(), p1 = F(), p2 = F(); 74 for (R int i = 1; i <= n; ++i) a[i] = F(), r[a[i]] = i, Fa[i] = lef[i] = rig[i] = i; 75 R int opcnt = 0; 76 for (R int i = 1; i <= m; ++i) 77 { 78 q[i] = (Query) {F(), F()}; 79 *++tot = (Chain) {last[q[i].r], i}; last[q[i].r] = tot; 80 op[++opcnt] = (Opt) {q[i].l - 1, i, -1}; 81 op[++opcnt] = (Opt) {q[i].r, i, 1}; 82 } 83 84 memset(bt, 0, (n + 1) << 2); top = 0; 85 for (R int i = 1; i <= n; ++i) 86 { 87 R int rr = i - 2; 88 while (top && a[st[top]] < a[i]) add(st[top--]); 89 if (top) add(st[top]); 90 st[++top] = i; 91 for (R Chain *iter = last[i]; iter; iter = iter -> next) 92 ans1[iter -> id] += query(q[iter -> id].r) - query(q[iter -> id].l - 1); 93 } 94 95 std::sort(op + 1, op + opcnt + 1); 96 for (R int i = 1; i <= n; ++i) 97 { 98 R int ps = r[i], f1; 99 if (ps != 1 && a[ps - 1] < i) lef[ps] = lef[f1 = Find(ps - 1)], Fa[f1] = ps;100 if (ps != n && a[ps + 1] < i) rig[ps] = rig[f1 = Find(ps + 1)], Fa[f1] = ps;101 }102 R int p = 1;103 while (op[p].x == 0) ++p;104 for (R int i = 1; i <= n; ++i)105 {106 // printf("%d %d\n", lef[i], rig[i]);107 ql = lef[i]; qr = rig[i];108 modify(1, 1, n);109 while (op[p].x == i)110 {111 ql = q[op[p].id].l; qr = q[op[p].id].r;112 ans2[op[p].id] += op[p].type * query(1, 1, n);113 ++p;114 }115 }116 for (R int i = 1; i <= m; ++i) printf("%lld\n", 1ll * ans1[i] * p1 + (ans2[i] - (q[i].r - q[i].l + 1) - ans1[i]) * p2);117 return 0;118 }119 /*120 9 4121 12 5122 2 0123 5 1124 5 2125 30126 39127 4128 13129 16130 131 */
4827: [Hnoi2017]礼物
把式子拆开完就是一个卷积和二次函数的形式,二次函数用对称轴公式来算,卷积用FFT来算。
1 #include <cstdio> 2 #include <algorithm> 3 #include <cmath> 4 5 #define R register 6 #define maxn 262145 7 #define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0) 8 typedef double db; 9 const db pi = acos(-1);10 struct Complex {11 db x, y;12 inline Complex operator - (const Complex &that) const {return (Complex) {x - that.x, y - that.y};}13 inline Complex operator * (const Complex &that) const {return (Complex) {x * that.x - y * that.y, x * that.y + that.x * y};}14 inline void operator += (const Complex &that) {x += that.x; y += that.y;}15 } w[maxn << 1];16 int N;17 void init()18 {19 R int h = N >> 1;20 for (R int i = 0; i < N; ++i) w[i + h] = (Complex) {cos(2 * pi / N * i), sin(2 * pi / N * i)};21 for (R int i = h; i--; ) w[i] = w[i << 1];22 }23 void bit_reverse(R Complex *a, R Complex *b)24 {25 for (R int i = 0; i < N; ++i) b[i] = a[i];26 for (R int i = 0, j = 0; i < N; ++i)27 {28 i > j ? std::swap(b[i], b[j]), 1 : 0;29 for (R int l = N >> 1; (j ^= l) < l; l >>= 1) ;30 }31 }32 void dft(R Complex *a)33 {34 for (R int l = 2, m = 1; m < N; l <<= 1, m <<= 1)35 for (R int i = 0; i < N; i += l)36 for (R int j = 0; j < m; ++j)37 {38 R Complex tmp = a[i + j + m] * w[j + m];39 a[i + j + m] = a[i + j] - tmp;40 a[i + j] += tmp;41 }42 }43 Complex a[maxn], b[maxn], c[maxn], ta[maxn], tb[maxn], tc[maxn];44 int main()45 {46 R int n, m, ans = 0x7fffffff, ret = 0, sum = 0; scanf("%d%d", &n, &m);47 for (R int i = 0; i < n; ++i) scanf("%lf", &a[i].x), sum -= a[i].x;48 for (R int i = 0; i < n; ++i) scanf("%lf", &b[i].x), sum += b[i].x;49 std::reverse(b, b + n);50 for (R int i = 0; i < n; ++i) b[i + n] = b[i];51 for (N = 1; N < (n << 1); N <<= 1);52 init();53 R int ccc = round((db) sum / n);54 55 for (R int i = 0; i < n; ++i) a[i].x += ccc, ret += a[i].x * a[i].x + b[i].x * b[i].x;56 // printf("%d %d\n", ccc, ret);57 bit_reverse(a, ta);58 bit_reverse(b, tb);59 dft(ta); dft(tb);60 for (R int i = 0; i < N; ++i) c[i] = ta[i] * tb[i];61 std::reverse(c + 1, c + N);62 bit_reverse(c, tc); dft(tc);63 // for (R int i = 0; i < N; ++i) printf("%lf %lf\n", tc[i].x, tc[i].y);64 for (R int i = 0; i < n; ++i) cmin(ans, (int) ret - (2 * tc[i + n].x / N));65 66 printf("%d\n", ans);67 return 0;68 }
Day2
4828: [Hnoi2017]大佬
玄学搜索题。搜索出来完用双指针扫一扫。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <map> 5 #include <bitset> 6 7 #define R register 8 #define maxn 110 9 int a[maxn], w[maxn]; 10 int f[maxn][maxn]; 11 const int oo = 1e8; 12 #define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0) 13 #define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b)) 14 #define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b)) 15 const int mod = 8260817; 16 typedef long long ll; 17 struct Queue { 18 int step, level, f; 19 } q[10000010]; 20 struct Hash { 21 Hash *next; 22 ll key; 23 } *last[mod], mem[mod], *tot = mem; 24 inline ll hash_key(R int a, R int b) 25 { 26 return 1ll * b * 233 + a; 27 } 28 inline bool insert(R int a, R int b) 29 { 30 R ll key = hash_key(a, b); 31 R int pos = key % mod; 32 for (R Hash *iter = last[pos]; iter; iter = iter -> next) 33 if (iter -> key == key) return 0; 34 *++tot = (Hash) {last[pos], key}; last[pos] = tot; 35 return 1; 36 } 37 struct Data { 38 int f, s; 39 inline bool operator < (const Data &that) const {return f < that.f;} 40 } st[maxn * maxn * maxn]; 41 int scnt, qu[30]; 42 int main() 43 { 44 R int n, m, mc; scanf("%d%d%d", &n, &m, &mc); 45 for (R int i = 1; i <= n; ++i) scanf("%d", &a[i]); 46 for (R int i = 1; i <= n; ++i) scanf("%d", &w[i]); 47 memset(f, -63, sizeof (f)); 48 f[0][mc] = 0; 49 for (R int i = 1; i <= n; ++i) 50 { 51 for (R int j = a[i]; j <= mc; ++j) 52 cmax(f[i][j - a[i]], f[i - 1][j] + 1), 53 cmax(f[i][dmin(j - a[i] + w[i], mc)], f[i - 1][j]); 54 } 55 R int Day = -1; 56 for (R int j = 0; j <= n; ++j) for (R int i = 0; i <= mc; ++i) cmax(Day, f[j][i]); 57 R int oo = 0; 58 for (R int i = 1; i <= m; ++i) scanf("%d", &qu[i]), cmax(oo, qu[i]); 59 60 R int head = 0, tail = 1; 61 q[1] = (Queue) {0, 0, 1}; 62 while (head < tail) 63 { 64 R Queue now = q[++head]; 65 if (insert(0, now.f)) st[++scnt] = (Data) {now.f, now.step + 1}; 66 if (now.step >= Day - 1) continue; 67 if (now.level > 0 && oo / now.level < now.f) continue; 68 if (insert(now.level + 1, now.f)) q[++tail] = (Queue) {now.step + 1, now.level + 1, now.f}; 69 70 if (1ll * now.f * now.level <= oo && now.f > 0) 71 { 72 if (insert(now.level, now.f * now.level)) 73 q[++tail] = (Queue) {now.step + 1, now.level, now.f * now.level}; 74 } 75 } 76 st[++scnt] = (Data) {0, 0}; 77 std::sort(st + 1, st + scnt + 1); 78 for (R int _ = 1; _ <= m; ++_) 79 { 80 R int c = qu[_], flag = 0; 81 if (Day <= 0) {puts("0"); continue;} 82 if (c <= Day) {puts("1"); continue;} 83 R int j = 0, mx = -oo * 2; 84 for (R int i = scnt; i; --i) 85 { 86 for (; j < scnt && st[j + 1].f + st[i].f <= c; ++j, cmax(mx, st[j].f - st[j].s)); 87 if (mx + st[i].f - st[i].s >= c - Day) 88 { 89 flag = 1; 90 break; 91 } 92 } 93 printf("%d\n", flag); 94 } 95 return 0; 96 } 97 /* 98 10 20 100 99 22 18 15 16 20 19 33 15 38 49100 92 14 94 92 66 94 1 16 90 51101 4102 5103 9104 338105 5222106 549107 7491108 9109 12110 3288111 3112 1113 2191114 833115 3116 6991117 2754118 3231119 360120 6121 122 1123 1124 1125 0126 0127 0128 0129 1130 1131 0132 1133 1134 0135 0136 1137 0138 0139 0140 0141 1142 */
4829: [Hnoi2017]队长快跑
看起来很nan,没去看。听说是一道不可做题。
4830: [Hnoi2017]抛硬币
广义Lucas定理。普通的Lucas一般指用于质数,广义的可以做质数的k次方的,然后用CRT(中国剩余定理)合并。
1 #include <cstdio> 2 3 #define R register 4 typedef long long ll; 5 int pw0[10], pw2[10], pw5[10]; 6 int counter; 7 inline int qpow(R int base, R ll power, R int mod) 8 { 9 R int ret = 1; 10 for (; power; power >>= 1, base = 1ll * base * base % mod) 11 power & 1 ? ret = 1ll * ret * base % mod : 0; 12 return ret; 13 } 14 int mod, k; 15 void exgcd(R int a, R int b, R int &x, R int &y) 16 { 17 if (!b) {x = 1, y = 0; return ;} 18 exgcd(b, a % b, y, x); 19 y -= a / b * x; 20 } 21 inline int inv(R int a, R int p) 22 { 23 R int x, y; 24 exgcd(a, p, x, y); 25 return (x % p + p) % p; 26 } 27 int f2[10][1024], f5[10][1953125]; 28 inline int fac(R ll n, R int fact, R int p, R int pk, R int *fk) 29 { 30 if (!n) return 1; 31 R ll y = n / pk; 32 R int ret = 1ll * qpow(fact, y, pk) * fk[n % pk] % pk; 33 return 1ll * fac(n / p, fact, p, pk, fk) * ret % pk; 34 } 35 int ft2[10], ft5[10]; 36 inline int Lucas(R ll n, R ll m, R int p, R int pk, R bool div) 37 { 38 R ll num = 0; 39 for (R ll tmp = p; tmp <= n; tmp *= p) num += n / tmp; 40 for (R ll tmp = p; tmp <= m; tmp *= p) num -= m / tmp; 41 for (R ll tmp = p; tmp <= n - m; tmp *= p) num -= (n - m) / tmp; 42 43 R int fact = p == 2 ? ft2[k] : ft5[k], 44 *fk = p == 2 ? f2[k] : f5[k], 45 fa = 1, fb, fc; 46 if (div) 47 { 48 if (p == 2) --num; 49 else fa = inv(2, pk); 50 } 51 if (num >= k) return 0; 52 53 fa = 1ll * fa * fac(n, fact, p, pk, fk) % pk; 54 fb = fac(m, fact, p, pk, fk); 55 fc = fac(n - m, fact, p, pk, fk); 56 fb = inv(fb, pk); fc = inv(fc, pk); 57 58 59 return 1ll * fa * fb % pk * fc % pk * qpow(p, num, pk) % pk; 60 } 61 inline int C(R ll n, R ll m, R bool div = 0) 62 { 63 if (m > n) return 0; 64 // printf("C(%lld, %lld) %d\n", n, m, div); 65 R int C2 = Lucas(n, m, 2, pw2[k], div); 66 R int C5 = Lucas(n, m, 5, pw5[k], div); 67 // printf("%d %d\n", C2, C5); 68 R int t2 = inv(pw5[k], pw2[k]); 69 R int t5 = inv(pw2[k], pw5[k]); 70 R int ans = (1ll * C2 * pw5[k] % mod * t2 + 1ll * C5 * pw2[k] % mod * t5) % mod; 71 // printf("%d\n", ans); 72 return ans; 73 } 74 int main() 75 { 76 R ll a, b; 77 pw0[0] = pw2[0] = pw5[0] = 1; 78 for (R int i = 1; i < 10; ++i) 79 pw0[i] = pw0[i - 1] * 10, 80 pw2[i] = pw2[i - 1] * 2, 81 pw5[i] = pw5[i - 1] * 5; 82 83 for (R int i = 1; i < 10; ++i) 84 { 85 f2[i][0] = 1; 86 for (R int j = 1; j < pw2[i]; ++j) 87 f2[i][j] = 1ll * f2[i][j - 1] * (j % 2 ? j : 1) % pw2[i]; 88 ft2[i] = f2[i][pw2[i] - 1]; 89 } 90 for (R int i = 1; i < 10; ++i) 91 { 92 f5[i][0] = 1; 93 for (R int j = 1; j < pw5[i]; ++j) 94 f5[i][j] = 1ll * f5[i][j - 1] * (j % 5 ? j : 1) % pw5[i]; 95 ft5[i] = f5[i][pw5[i] - 1]; 96 } 97 98 while (scanf("%lld%lld%d", &a, &b, &k) != EOF) 99 {100 char str[10];101 R int ans = 0;102 mod = pw0[k];103 ans = qpow(2, a + b - 1, mod);104 if (a == b) (ans += mod - C(a + a, a, 1)) %= mod;105 else106 {107 if (((a + b) & 1) == 0) (ans += C(a + b, (a + b) / 2, 1)) %= mod;108 for (R ll j = (a + b) / 2 + 1; j < a; ++j)109 (ans += C(a + b, j)) %= mod;110 }111 sprintf(str, "%%0%dd\n", k);112 printf(str, ans);113 }114 return 0;115 }116 /*117 488754688118 1000000000000000 999999999990000 9119 1000000000000000 999999999990000 8120 1000000000000000 999999999990000 7121 1000000000000000 999999999990000 6122 1000000000000000 999999999990000 5123 1000000000000000 999999999990000 4124 1000000000000000 999999999990000 3125 1000000000000000 999999999990000 2126 1000000000000000 999999999990000 1127 */
Hnoi2017试题泛做
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。