题解:P11845 [USACO25FEB] Min Max Subarrays P

· · 题解

首先看到这种比较复杂的比大小的问题,尝试套路的扫描一个值域然后将序列转为 01 序列。

$Ans=\sum_{v\ge 1}g(v)$,$g(v)$ 表示答案大于等于 $v$ 的区间个数。 将 $a_i\ge v$ 的看作 $1$,其他看作 $0$,$g(v)$ 即是这个 $01$ 序列的所有子区间中操作完得到 $1$ 的子区间按个数。 现在问题就可做多了,考虑刻画什么样的序列最终可以得到 $1$。 首先你要得到 $1$,那么你的序列肯定不能是全 $0$,这是第一个条件。 我们先将极长同色段给划分出来,这样会比较好分析。 考虑操作取 $\min$ 操作的时候我们肯定尽量去给相邻两个 $0$ 取 $\min$,可以使一段长度大于等于 $2$ 的 $0$ 段的长度减一,同时下一次的取 $\max$ 操作我们肯定尽量不操作相邻两个 $1$,这样也可以使一段 $0$ 段的长度减一。 通过上面的分析,我们发现 $1$ 似乎比较难被删除,那可以合理猜测 $1$ 的个数比较多的时候是不是一定就可以得到 $1$,首先只有一个 $1$ 显然不够多(反例:$01$),两个也不够(反例:$0110$),那么三个呢,好像够了,通过一些简单分讨可以证明的确够。 考虑证明,首先对于所有 $0$ 段,我们可以通过上面分析的操作在一回合内(一次取 $\min$ 一次取 $\max$)将一段的长度减二,所以我们就只用讨论 $-1-1-1-$ 的情况,$-$ 表示可以存在单个 $0$ 或者一个都不存在,其中很多情况都是重复或者显然的(手玩之前最好先证明 $101,01010,110$ 都是合法的,后续很多分讨都可以将序列中某一段奇数长度的区间直接看作 $0$ 后套用这几个小结论),手玩一下可以发现都可以合并出 $1$。 剩下的情况就只有 $1$ 的个数为 $1$ 或 $2$ 了,先来看个数为 $1$,分讨这个 $1$ 左右两侧 $0$ 的奇偶性,可以发现只有在奇偶性不同时,即区间长度为偶数,或者区间为 $010$ 的时候非法。 再来看个数为 $2$,同样分讨左中右的 $0$ 的个数的奇偶性,虽然看起来有 $8$ 中情况,但是其中有重复的还有非常显然的,所以~~分讨并不复杂~~,分讨完后可以发现只有一下序列非法:$1010,001010,0110,010010,0101,010100$。 总结一下非法的序列为:$010,1010,001010,0110,010010,0101,010100$,以及只有一个 $1$ 且长度为偶数的序列,还有不存在一的区间。 从小到达扫描 $v$,每次将一个位置的 $1$ 改为 $0$,前面那七种非法的区间个数都可以直接 $\mathcal{O}(1)$ 计算变化量,后面这个非法的区间直接在每个 $1$ 那里记录上一个以及下一 $1$ 的位置,也可以 $\mathcal{O}(1)$ 计算变化量,最后维护一下 $0$ 段,将不存在一的区间减掉即可。 时间复杂度 $\mathcal{O}(n)$。 ```cpp #include<ctime> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> typedef long long ll; using namespace std; bool ST; namespace fast_IO { #define IOSIZE 100000 static unsigned int precision = 6, POW[10] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000}; // 鍚戜笅鍙栨暣鍒板皬鏁扮偣鍚庣 precision 浣? static char obuf[IOSIZE], *p3 = obuf; #ifdef ONLINE_JUDGE static char ibuf[IOSIZE], *p1 = ibuf, *p2 = ibuf; #define getchar() ((p1==p2)and(p2=(p1=ibuf)+fread(ibuf,1,IOSIZE,stdin),p1==p2)?(EOF):(*p1++)) #endif #define putchar(x) ((p3==obuf+IOSIZE)&&(fwrite(obuf,p3-obuf,1,stdout),p3=obuf),*p3++=x) inline int64_t read() { int64_t s = 0; int w = 1; char ch; while (ch = getchar(), !(ch>47 and ch<58) and (ch != EOF)) if (ch == '-') w = -1; if (ch == EOF) return false; while ((ch>47 and ch<58)) s = s * 10 + ch - 48, ch = getchar(); return s * w; } template<typename T> static inline bool read(T &s) { s = 0; int w = 1; char ch; while (ch = getchar(), !(ch>47 and ch<58) and (ch != EOF)) if (ch == '-') w = -1; if (ch == EOF) return false; while ((ch>47 and ch<58)) s = s * 10 + ch - 48, ch = getchar(); return s *= w, true; } template<typename T> static inline void print(T x) { if (x < 0) putchar('-'), x = -x; if (x > 9) print(x / 10); putchar(x % 10 + 48); } static inline bool read(char &s) { while (s = getchar(), isspace(s) and s != EOF); return s != EOF; } static inline void print(char x) { putchar(x); } static inline bool read(char *s) { char ch; while (ch = getchar(), (ch<33) && ch != EOF); if (ch == EOF) return false; while (!(ch<33) and (ch != EOF)) *s++ = ch, ch = getchar(); *s = '\0'; return true; } static inline void print(char *x) { while (*x) putchar(*x++); } static inline void print(const char *x) { for (int i = 0; x[i]; i++) putchar(x[i]); } static inline bool read(std::string& s) { s = ""; char ch; while (ch = getchar(), (ch<33) and ch != EOF); if (ch == EOF) return false; while (!(ch<33)) s += ch, ch = getchar(); return true; } static inline void print(std::string x) { for (int i = 0, n = x.size(); i < n; i++) putchar(x[i]); } static inline bool read(bool &b) { char ch; while(ch=getchar(), (ch<33) and ch != EOF); return ch == EOF ?false :(b=ch^48, true); } static inline void print(bool b) { putchar(b+48); } static inline bool read(double &x) { char ch = getchar(); int f = 1; for(; (ch<48 or 57<ch) and (ch != EOF); ch=getchar()) if(ch == '-') f = -1; if(ch == EOF) return false; for(x=0; 47<ch and ch<58; ch=getchar()) x = x*10 + (ch^48); if(ch != '.') return x *= f, true; double y = 0.1; for(ch=getchar(); 47<ch and ch<58; ch=getchar()) x += y*(ch^48), y /= 10; return x *= f, true; } static inline void print(double x) { if(x < 0) putchar('-'), x = -x; if(!precision) print((unsigned long long)(x-(unsigned long long)(x)>=0.5 ?x+1 :x)); else { unsigned long long xx = x; double y = ((x-xx)*POW[precision]); unsigned long long yy = (y-(unsigned long long)(y)>=0.5 ?y+1 :y); if(yy == POW[precision]) xx++, yy = 0; print(xx), putchar('.'); for(int j=precision-1; ~j; j--) putchar(48+yy/POW[j]%10); } } template<typename T, typename... T1> static inline int read(T& a, T1&... other) { return read(a) + read(other...); } template<typename T, typename... T1> static inline void print(T a, T1... other) { print(a), print(other...); } static struct Fast_IO { bool flag = 1; inline ~Fast_IO() { fwrite(obuf, p3 - obuf, 1, stdout); } // inline void SetPrecision(int x) { if(x > 9) throw runtime_error("Precision too high!"); else if(x < 0) throw runtime_error("Precision too low!"); else precision = x; } // 娴偣鏁扮簿搴﹁涓?x锛屽嵆绮剧‘鍒板皬鏁扮偣鍚?x 浣嶃€? inline operator bool() { return flag; } } io; Fast_IO& operator >> (Fast_IO &io, char *b) { return io.flag &= read(b), io; } template<typename T> static Fast_IO& operator >> (Fast_IO &io, T &b) { return io.flag &= read(b), io; } template<typename T> static Fast_IO& operator << (Fast_IO &io, T b) { return print(b), io; } #define cout io #define cin io #define endl '\n' } using namespace fast_IO; namespace furina{ const int N = 1e6, inf = 0x7fffffff >> 1; int n; int a[N + 10], b[N + 10], c[N + 10]; vector<int> vt[N + 10]; struct segment{ int l, r; } s[N + 10]; int bl[N + 10]; int lst[N + 10], nxt[N + 10]; int main(){ cin >> n; for(int i = 1; i <= n; i++) cin >> a[i], vt[a[i]].push_back(i); ll ans = 0, res = -1, sum1 = 0, sum2 = 0, sum3 = 0; for(int i = 0; i <= n + 1; i++) b[i] = 1, s[bl[i] = i] = {-1, -1}, lst[i] = i - 1, nxt[i] = i + 1; auto update = [&](const int &l, const int &type) -> void { if(l < 1) return; if(l + 2 <= n && b[l] == 0 && b[l + 1] == 1 && b[l + 2] == 0) sum2 += type; if(l + 3 <= n && b[l] == 0 && b[l + 1] == 1 && b[l + 2] == 0 && b[l + 3] == 1) sum2 += type; if(l + 3 <= n && b[l] == 1 && b[l + 1] == 0 && b[l + 2] == 1 && b[l + 3] == 0) sum2 += type; if(l + 3 <= n && b[l] == 0 && b[l + 1] == 1 && b[l + 2] == 1 && b[l + 3] == 0) sum2 += type; if(l + 5 <= n && b[l] == 0 && b[l + 1] == 1 && b[l + 2] == 0 && b[l + 3] == 1 && b[l + 4] == 0 && b[l + 5] == 0) sum2 += type; if(l + 5 <= n && b[l] == 0 && b[l + 1] == 0 && b[l + 2] == 1 && b[l + 3] == 0 && b[l + 4] == 1 && b[l + 5] == 0) sum2 += type; if(l + 5 <= n && b[l] == 0 && b[l + 1] == 1 && b[l + 2] == 0 && b[l + 3] == 0 && b[l + 4] == 1 && b[l + 5] == 0) sum2 += type; }; auto get0 = [&](const int &x) -> int { return (x >> 1) + 1; }; auto get1 = [&](const int &x) -> int { return (x + 1) >> 1; }; auto calc = [&](const int &x) -> ll { if(x < 1 || x > n) return 0; ll res = 0; int L = x - lst[x] - 1, R = nxt[x] - x - 1; //0<=l<=L,0<=r<=R,(l+r)&1=1 res += 1ll * get0(L) * get1(R) + 1ll * get1(L) * get0(R); return res; }; for(int i = 1; i <= n; i++){ if(res != -1){ ans += res; continue; } res = 1ll * n * (n + 1) / 2 - sum1 - sum2 - sum3; ans += res; for(int j : vt[i]){//赋值为0 for(int k = 0; k < 6; k++) update(j - k, -1); b[j] = 0; for(int k = 0; k < 6; k++) update(j - k, 1); sum3 -= calc(j) + calc(lst[j]) + calc(nxt[j]); nxt[lst[j]] = nxt[j], lst[nxt[j]] = lst[j]; sum3 += calc(lst[j]) + calc(nxt[j]); if(b[j - 1] && b[j + 1]) s[bl[j]] = {j, j}, sum1++; else if(!b[j - 1] && !b[j + 1]){ int L = s[bl[j - 1]].l, R = s[bl[j + 1]].r; s[bl[L] = bl[R] = bl[j]] = {L, R}; sum1 += 1ll * (j - L + 1) * (R - j + 1); } else if(!b[j - 1]){ int L = s[bl[j - 1]].l, R = j; s[bl[L] = bl[R] = bl[j]] = {L, R}; sum1 += R - L + 1; } else if(!b[j + 1]){ int L = j, R = s[bl[j + 1]].r; s[bl[L] = bl[R] = bl[j]] = {L, R}; sum1 += R - L + 1; } } res = -1; } cout << ans << '\n'; return 0; } } bool ED; signed main(){ furina::main(); cerr << 1000. * clock() / CLOCKS_PER_SEC << "ms" << '\n'; cerr << (abs(&ST - &ED) >> 20) << "mb" << '\n'; return 0; } /* g++ -o furina furina.cpp -std=c++14 -Wall -O2 -lm -Wl,--stack=2000000000 & furina */ ```