发明者:队爷莫涛node
一种“优雅的暴力”ios
因善于无限卡常而闻名OI界算法
主要思想也十分简单:函数
暴力,也用到了排序,分块。优化
实际的操做方式就是经过改变枚举区间的顺序来达到优化复杂度的目的spa
虽然听上去很玄学,但却十分有效.net
复杂度在 \(O(n^{\frac{3}{2}})\) 左右code
通常是将查找区间分红 \(n^{\frac{1}{2}}\) 块blog
更优的复杂度能够进行按块奇偶排序来实现排序
普通莫队只支持离线操做,在线操做仍是十分鸡肋的
但难不倒咱们OIer
后人又总结出回滚莫队,带修莫队,树上莫队等多种方法,还没学,先咕咕着
要注意枚举的顺序,详见\(Oi-Wiki\)中关于四个循环问题的讨论,主要思路是将区间先扩大再缩小
利用莫队思想对全部查询的区间进行分块排序,顺便加上奇偶优化
每增长一个数,它对答案的贡献等于 \(c^{2} - (c - 1)^{2}\)
每减掉一个数,它对答案的贡献等于 \((c - 1)^{2} - c^{2}\)
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define LL long long using namespace std; const int MAXN = 5e4+5; const int INF = 1; const int mod = 1; struct node{ int l, r, bh; }b[MAXN]; int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return s * w; } int n, m, k, qrtn; int a[MAXN]; LL Ans[MAXN], ans; int cnt[MAXN]; bool cmp(node x, node y){ return x.l / qrtn == y.l / qrtn ? (x.l / qrtn % 2 == 0 ? x.r > y.r : x.r < y.r) : x.l < y.l; } void add(LL pos){ int x = ++cnt[a[pos]]; ans -= (x - 1) * (x - 1); ans += x * x; } void del(LL pos){ int x = --cnt[a[pos]]; ans -= (x + 1) * (x + 1); ans += x * x; } int main() { n = read(), m = read(), k = read(); for(int i = 1; i <= n; ++i) a[i] = read(); for(int i = 1; i <= m; ++i){ b[i].l = read(), b[i].r = read(); b[i].bh = i; } qrtn = sqrt(n + 0.5); sort(b + 1, b + m + 1, cmp); int l = 1, r = 0; for(int i = 1; i <= m; ++i){ while(l > b[i].l) add(--l); while(r < b[i].r) add(++r); while(l < b[i].l) del(l++); while(r > b[i].r) del(r--); Ans[b[i].bh] = ans; } for(int i = 1; i <= m; ++i){ printf("%lld\n", Ans[i]); } return 0; }
不难发现,全部状况总数等于 \(len * (len - 1) / 2\),其中 \(len\) 是区间长度
设函数 \(c(x) = x * (x - 1) / 2\) ,
则每加一个元素对其的贡献为 \(c(x) - c(x - 1)\)
同理减一个元素的贡献 \(c(x - 1) - c(x)\)
最后的答案等于分子和分母的比,分子为每一个元素的贡献,分母为 \(c(len)\),注意通分和特判特殊状况
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define LL long long using namespace std; const int MAXN = 5e4+5; const int INF = 1; const int mod = 1; struct node{ int l, r, bh; }b[MAXN]; inline int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return s * w; } int n, m, qrtn; int a[MAXN]; int cnt[MAXN]; LL Ans[MAXN], ans; LL Ansfm[MAXN]; inline bool cmp(node x, node y){ return x.l / qrtn == y.l / qrtn ? (x.l / qrtn % 2 == 0 ? x.r > y.r : x.r < y.r) : x.l < y.l; } inline LL Gcd(LL x, LL y){ return y == 0 ? x : Gcd(y, x % y); } inline LL c(LL x){ return x * (x - 1) / 2; } inline void del(LL pos){ int x = --cnt[a[pos]]; ans -= c(x + 1); ans += c(x); } inline void add(LL pos){ int x = ++cnt[a[pos]]; ans -= c(x - 1); ans += c(x); } int main() { n = read(), m = read(); for(register int i = 1; i <= n; ++i) a[i] = read(); for(register int i = 1; i <= m; ++i){ b[i].l = read(), b[i].r = read(); b[i].bh = i; } qrtn = sqrt(n + 0.5); sort(b + 1, b + m + 1, cmp); int l = 0, r = -1; for(register int i = 1; i <= m; ++i){ while(l > b[i].l){ l--; add(l); } while(r < b[i].r){ r++; add(r); } while(l < b[i].l){ del(l); l++; } while(r > b[i].r){ del(r); r--; } Ans[b[i].bh] = ans;//fenzi Ansfm[b[i].bh] = c(r - l + 1);//fenmu } // cout<<qrtn<<endl; for(int i = 1; i <= m; ++i){ if(!Ans[i]) printf("0/1\n"); else{ LL gcd = Gcd(Ans[i], Ansfm[i]); printf("%lld/%lld\n", Ans[i] / gcd, Ansfm[i] / gcd); } } return 0; }
用 \(ans\) 来记录有几个数相同
若是增长一个元素 \(x\) 后,\(cnt[x] == 2\) ,\(ans++\)
若是删掉一个元素 \(x\) 后,\(cnt[x] == 1\) ,\(ans--\)
最后统计答案时,\(ans == 1\),为 \(Yes\),不然为 \(No\)
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define LL long long using namespace std; const int MAXN = 1e5+5; const int INF = 1; const int mod = 1; struct node{ int l, r, bh; }b[MAXN]; int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return s * w; } int n, m, k, qrtn; int a[MAXN]; LL Ans[MAXN], ans; int cnt[MAXN]; bool cmp(node x, node y){ return x.l / qrtn == y.l / qrtn ? (x.l / qrtn % 2 == 0 ? x.r > y.r : x.r < y.r) : x.l < y.l; } void add(LL pos){ int x = ++cnt[a[pos]]; if(x == 2) ans++; } void del(LL pos){ int x = --cnt[a[pos]]; if(x == 1) ans--; } int main() { n = read(), m = read(); for(int i = 1; i <= n; ++i) a[i] = read(); for(int i = 1; i <= m; ++i){ b[i].l = read(), b[i].r = read(); b[i].bh = i; } qrtn = sqrt(n + 0.5); sort(b + 1, b + m + 1, cmp); int l = 1, r = 0; for(int i = 1; i <= m; ++i){ while(l > b[i].l) add(--l); while(r < b[i].r) add(++r); while(l < b[i].l) del(l++); while(r > b[i].r) del(r--); Ans[b[i].bh] = (ans == 0) ? 1 : 0; } for(int i = 1; i <= m; ++i){ Ans[i] == 1 ? printf("Yes\n") : printf("No\n"); } return 0; }
每加一个数,统计个数,看看有没有新的贡献。
注意每加一个数或减一个数都有可能作出贡献,若是多加了也要将相应的贡献减掉
没加任何优化的莫队,当时第一次写,写的比较丑
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 1e5+5; const int INF = 1; const int mod = 1; struct node{ int l, r, bh, ans; bool operator < (const node &b) const {return l == b.l ? r < b.r : l < b.l; } }b[MAXN]; int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return s * w; } int n, m, l = 1, r = 0, ans = 0; int a[MAXN], cnt[MAXN]; bool vis[MAXN]; bool cmp(node x, node y){return x.l == y.l ? x.r < y.r : x.l < y.l; } bool cmp2(node x, node y){return x.bh < y.bh; } int main() { n = read(), m = read(); for(int i = 1; i <= n; ++i) a[i] = read(), a[i] = a[i] > 1e5 ? 0 : a[i]; for(int i = 1; i <= m; ++i) b[i].l = read(), b[i].r = read(), b[i].bh = i; sort(b + 1, b + m + 1, cmp); for(int i = 1; i <= m; ++i){ while(l < b[i].l) { cnt[a[l]]--; l++; if(a[l - 1] == cnt[a[l - 1]] && !vis[a[l - 1]]) ans++, vis[a[l - 1]] = 1; if(a[l - 1] != cnt[a[l - 1]] && vis[a[l - 1]]) ans--, vis[a[l - 1]] = 0; } while(r < b[i].r) { cnt[a[++r]]++; if(a[r] == cnt[a[r]] && !vis[a[r]]) ans++, vis[a[r]] = 1; if(a[r] != cnt[a[r]] && vis[a[r]]) ans--, vis[a[r]] = 0; } while(r > b[i].r){ cnt[a[r]]--; r--; if(a[r + 1] == cnt[a[r + 1]] && !vis[a[r + 1]]) ans++, vis[a[r + 1]] = 1; if(a[r + 1] != cnt[a[r + 1]] && vis[a[r + 1]]) ans--, vis[a[r + 1]] = 0; } b[i].ans = ans; } sort(b + 1, b + m + 1, cmp2); for(int i = 1; i <= m; ++i){ printf("%d\n", b[i].ans); } return 0; }
CF617E XOR and Favorite Number
/* Work by: Suzt_ilymics Knowledge: ?? Time: O(??) */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define LL long long #define int long long using namespace std; const int MAXN = 1e5+5; const int kMax = 1e6+6; const int INF = 1; const int mod = 1; struct node{ int l, r, bh; }b[MAXN]; int n, m, k, qrtn; int a[MAXN]; LL Ans[MAXN], ans; int cnt[kMax << 1]; int read(){ int s = 0, w = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0' , ch = getchar(); return s * w; } bool cmp(node x, node y) { return x.l / qrtn == y.l / qrtn ? x.r < y.r : x.l < y.l; } void add(int pos){ ans += (LL)cnt[a[pos] ^ k]; ++cnt[a[pos]]; } void del(int pos){ --cnt[a[pos]]; ans -= (LL)cnt[a[pos] ^ k]; } signed main() { n = read(), m = read(), k = read(); for(int i = 1; i <= n; ++i) a[i] = read(), a[i] ^= a[i - 1]; for(int i = 1; i <= m; ++i){ b[i].l = read(), b[i].r = read(), b[i].bh = i; } qrtn = sqrt(n + 0.5); sort(b + 1, b + m + 1, cmp); int l = 0, r = -1; cnt[0] = 1; for(int i = 1; i <= m; ++i){ while(l > b[i].l) l--, add(l - 1); while(r < b[i].r) r++, add(r); while(l < b[i].l) del(l - 1), l++; while(r > b[i].r) del(r), r--; Ans[b[i].bh] = ans; } for(int i = 1; i <= m; ++i){ printf("%lld\n", Ans[i]); } return 0; }