感觉今天题目都挺有意思的可能以后还会碰到类似的 (Fop_zz就是厉害)
大意:给出n根木棍,每次可以把一根长为x的木棍分为 y 和 x - y,使得最终所有的长度出现的次数都为偶数次,例如 1 1 4 就是不合法的, 而 1 1 2 2 是合法的(操作次数小于等于n)
sol:因为木棍只可能变短,所以我维护了一个大根堆,每次查询最大值和次大值,使最大值变为和次大值一样,再把两者的差压入堆中,易证最多n次
#include <cmath> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define int long long int n, a[100005], cnt = 0, ans[100005][2]; int heap[100005], size = 0; inline void Up(int x) { while(x > 1) if (heap[x] > heap[x / 2]) swap(heap[x], heap[x / 2]), x /= 2; else break; } inline void Down(int x) { int y = x * 2; while (y <= size) { if (heap[y] < heap[y + 1] && y < size) y++; if (heap[x] < heap[y]) swap(heap[x], heap[y]), x = y, y = x * 2; else break; } } inline void Insert(int x) { heap[++size] = x; Up(size); } inline int GetTop() { return heap[1]; } inline void PopTop() { swap(heap[1], heap[size]); size--; Down(1); } signed main() { scanf("%lld", &n); int sum = 0; for(int i = 1; i <= n; i++) scanf("%lld", &a[i]), sum += a[i]; if (sum & 1) { printf("-1\n"); return 0; } for(int i = 1; i <= n; i++) Insert(a[i]); for(;size > 1;) { int x = GetTop(); PopTop(); int y = GetTop(); PopTop(); if (x != y) ans[++cnt][0] = x, ans[cnt][1] = x - y, Insert(x - y); } if (size == 1) { int x = GetTop(); PopTop(); ans[++cnt][0] = x / 2; ans[cnt][1] = x / 2; } printf("%lld\n", cnt); for(int i = 1; i <= cnt; i++) printf("%lld %lld\n", ans[i][0], ans[i][1]); }
类似于石子合并的经典题,只不过套了个高精,还要压位
#include <cmath> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define Mod 1000000007 #define int long long int power = 8, base = 100000000; int n, b[305], g[305][305]; bool vis[305][305]; inline int sqr(int x){return x * x;} struct Bignum { int a[30]; Bignum(){memset(a, 0, sizeof a);} Bignum(int num) { memset(a, 0, sizeof a); while(num) a[++a[0]] = num % base, num /= base; } inline void print() { printf("%lld", a[a[0]]); for(int i = a[0] - 1; i >= 1; i--) { int tmp = a[i]; if (tmp < 10000000) putchar('0'); if (tmp < 1000000) putchar('0'); if (tmp < 100000) putchar('0'); if (tmp < 10000) putchar('0'); if (tmp < 1000) putchar('0'); if (tmp < 100) putchar('0'); if (tmp < 10) putchar('0'); printf("%lld",tmp); } printf("\n"); } }f[305][305], zero, ans, one; inline bool operator <(const Bignum &p, const Bignum &q) { if (p.a[0] < q.a[0]) return true; if (p.a[0] > q.a[0]) return false; for(int i = p.a[0]; i >= 1; i--) if (p.a[i] != q.a[i]) return p.a[i] < q.a[i]; return false; } inline Bignum max(Bignum p, Bignum &q) { return (p < q) ? q : p; } inline Bignum operator +(const Bignum &p, const Bignum &q) { Bignum pp; pp.a[0] = max(p.a[0], q.a[0]); for(int i = 1; i <= pp.a[0]; i++) { pp.a[i] += p.a[i] + q.a[i]; pp.a[i + 1] += pp.a[i] / base; pp.a[i] %= base; } if (pp.a[pp.a[0] + 1]) pp.a[0]++; return pp; } inline Bignum dp(int l, int r) { if (vis[l][r]) return f[l][r]; if (l == r) return Bignum(0); vis[l][r] = 1; for(int i = l + 1; i <= r; i++) f[l][r] = max(f[l][r], dp(l, i - 1) + dp(i, r) + (Bignum)(sqr(g[l][i - 1] - g[i][r]))); return f[l][r]; } signed main() { memset(vis, 0, sizeof vis); scanf("%lld", &n); for(int i = 1; i <= n; i++) scanf("%lld", &b[i]); for(int i = 1; i <= n; i++) { int now = 1LL; for(int j = i; j <= n; j++) now = now * b[j] % Mod, g[i][j] = now; } dp(1, n).print(); }
线段树 不想说发
因为是and操作,一个数最多改log次, 暴力单点修改复杂度n*log(n)可过
#include <bits/stdc++.h> using namespace std; #define int long long inline int read() { char ch; int flag = 0, s = 0; while(!isdigit(ch)) flag |= (ch== '-'), ch = getchar(); while(isdigit(ch)) s = (s << 3) + (s << 1) + (ch - '0'), ch = getchar(); return flag ? -s : s; } int n, m, a[100005]; struct xds { int l, r, ma, sum; }Tree[100005 << 3]; inline void pushup(int x) { Tree[x].ma = max(Tree[x << 1].ma, Tree[x << 1 | 1].ma); Tree[x].sum = (Tree[x << 1].sum | Tree[x << 1 | 1].sum); } inline void build(int l, int r, int x) { Tree[x].l = l; Tree[x].r = r; if (l == r) { Tree[x].ma = a[l]; Tree[x].sum = a[l]; return; } int mid = (l + r) >> 1; build(l, mid, x << 1); build(mid + 1, r, x << 1 | 1); pushup(x); } inline void change(int pos, int x, int val) { if (Tree[x].l == Tree[x].r) { Tree[x].ma = val; Tree[x].sum = val; return; } int mid = (Tree[x].l + Tree[x].r) >> 1; if (pos <= mid) change(pos, x << 1, val); else change(pos, x << 1 | 1, val); pushup(x); } inline void updata(int l, int r, int x, int val) { if ((Tree[x].sum & val) == Tree[x].sum) return; if (Tree[x].l == Tree[x].r) { Tree[x].ma &= val; Tree[x].sum &= val; return; } int mid = (Tree[x].l + Tree[x].r) >> 1; if (r <= mid) updata(l, r, x << 1, val); else if (l > mid) updata(l, r, x << 1 | 1, val); else updata(l, mid, x << 1, val), updata(mid + 1, r, x << 1 | 1, val); pushup(x); } inline int query(int l, int r, int x) { if (l <= Tree[x].l && Tree[x].r <= r) return Tree[x].ma; int mid = (Tree[x].l + Tree[x].r) >> 1, res = 0; if (r <= mid) return query(l, r, x << 1); else if (l > mid) return query(l, r, x << 1| 1); else return max(query(l, mid, x<<1), query(mid + 1, r, x << 1 | 1)); } signed main() { n = read(); m = read(); for(int i = 1; i <= n; i++) a[i] = read(); build(1, n, 1); char s[20]; for(int i = 1, l, r, x; i <= m; i++) { scanf("%s", s + 1); l = read(); r = read(); if (s[1] == 'C') change(l, 1, r); if (s[1] == 'U') x = read(), updata(l, r, 1, x); if (s[1] == 'A') printf("%lld\n", query(l, r, 1)); } }