1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
| #include <cstdio> #include <algorithm> #include <cctype> #include <cstring> #include <cmath> using namespace std; typedef long long int64; inline int read(int f = 1, int x = 0, char ch = ' ') { while(!isdigit(ch = getchar())) if(ch == '-') f = -1; while(isdigit(ch)) x = x*10+ch-'0', ch = getchar(); return f*x; } const int N = 1e6+5; const int64 INF = 0x3f3f3f3f3f3f3f3fLL; int n, m, c, h[N]; int64 ans = INF, f[N], s1[N], s2[N]; int s[N], top; int64 calc(int i, int j, int hk) { int64 A = i-j-1; int64 B = -2*(s1[i-1]-s1[j])-(i!=n+1)*c-(j!=0)*c; int64 C = s2[i-1]-s2[j]+1ll*(i!=n+1)*h[i]*c+1ll*(j!=0)*h[j]*c; int x = (int)round(-1.0*double(B)/double(A)/2.0); x = max(x, hk); if(i != n+1) x = min(x, h[i]); if(j != 0) x = min(x, h[j]); return A*x*x+B*x+C; } int main() { freopen("construct.in", "r", stdin); freopen("construct.out", "w", stdout); n = read(), c = read(); for(int i = 1; i <= n; ++i) h[i] = read(), m = max(h[i], m), s1[i] = s1[i-1]+h[i], s2[i] = s2[i-1]+1ll*h[i]*h[i]; s[++top] = 0; h[0] = h[n+1] = m+1; for(int i = 1; i <= n+1; ++i) { f[i] = f[i-1]+1ll*(i != 1&&i != n+1)*c*abs(h[i]-h[i-1]); while(top&&h[s[top]] <= h[i]) { if(top > 1) f[i] = min(f[i], f[s[top-1]]+calc(i, s[top-1], h[s[top]])); --top; } s[++top] = i; } printf("%lld\n", f[n+1]); return 0; } ```
## 蔬菜 > 求矩形区域内颜色的出现次数的平方和
玄学题目,正解是按照出现次数分组,然而莫队可以水过去,但考场上看到转移是 $O(n)$ 就果断放弃了,但确实能过 ㄟ( ▔, ▔ )ㄏ
莫队复杂度 $O(qT+\frac{n^2}{T}+\frac{n^3}{T^2}+\frac{n^4}{T^3})$ 差不多在 $T = \frac{n}{q^{\frac{1}{4}}}$ 时最优
最后,记得跳指针时先扩张再减小
```cpp #include <cstdio> #include <algorithm> #include <cctype> #include <cmath> using namespace std; typedef long long int64; inline int read(int f = 1, int x = 0, char ch = ' ') { while(!isdigit(ch = getchar())) if(ch == '-') f = -1; while(isdigit(ch)) x = x*10+ch-'0', ch = getchar(); return f*x; } const int M = 2e2+5, N = 1e6+5; int n, m, t; int _[N], tot; int c[M][M]; int bel[N], T; struct Query { int px, py, qx, qy, p; Query(int px = 0, int py = 0, int qx = 0, int qy = 0, int p = 0):px(px), py(py), qx(qx), qy(qy), p(p) {} bool operator < (const Query &_) const { if(bel[px] != bel[_.px]) return px < _.px; if(py != _.py) return py < _.qy; if(qx != _.qx) return qx < _.qx; return qy < _.qy; } }q[N]; int ans[N]; int px = 1, py = 1, qx = 1, qy = 1, cnt[N], ret = 1; void cUpdate(int x, int d) { for(int y = py; y <= qy; ++y) if(c[x][y]) ret -= cnt[c[x][y]]*cnt[c[x][y]], cnt[c[x][y]] += d, ret += cnt[c[x][y]]*cnt[c[x][y]]; } void rUpdate(int y, int d) { for(int x = px; x <= qx; ++x) if(c[x][y]) ret -= cnt[c[x][y]]*cnt[c[x][y]], cnt[c[x][y]] += d, ret += cnt[c[x][y]]*cnt[c[x][y]]; } int main() { n = read(), m = read(), t = read(); for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) c[i][j] = read(), _[++tot] = c[i][j]; sort(_+1, _+tot+1); for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) c[i][j] = lower_bound(_+1, _+tot+1, c[i][j])-_; T = int(1.0*n/pow(t, 0.25))+1; for(int i = 1; i <= n; ++i) bel[i] = i/T+1; for(int i = 1; i <= t; ++i) { int px = read(), py = read(), qx = read(), qy = read(); q[i] = Query(px, py, qx, qy, i); } sort(q+1, q+1+t); ++cnt[c[1][1]]; for(int i = 1; i <= t; ++i) { while(px > q[i].px) --px, cUpdate(px, 1); while(qx < q[i].qx) ++qx, cUpdate(qx, 1); while(px < q[i].px) cUpdate(px, -1), ++px; while(qx > q[i].qx) cUpdate(qx, -1), --qx;
while(py > q[i].py) --py, rUpdate(py, 1); while(qy < q[i].qy) ++qy, rUpdate(qy, 1); while(py < q[i].py) rUpdate(py, -1), ++py; while(qy > q[i].qy) rUpdate(qy, -1), --qy; ans[q[i].p] = ret; } for(int i = 1; i <= t; ++i) printf("%d\n", ans[i]); return 0; }
|