標籤:opera void names 莫隊 += 演算法 更新 main 離線操作
原理
1、離線操作。
2、劃分成若干塊,將區間先按塊排序,塊內按區間右邊界排序。塊大小一般為sqrt(n)。
3、按照排序後的區間進行操作,不斷進行區間轉移,更新答案。
題目
1、小Z的襪子(hose) HYSBZ - 2038
題意:有n只襪子,求區間內顏色相同的兩隻襪子的機率。
思路:對於區間[l,r],其機率為sum(cnt[i]*(cnt[i-1])|i∈val[l,..,r])/[(r-l+1)*(r-l)]。按照莫隊的思想更新分子即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 using namespace std; 6 const int maxn = 5e5 + 10; 7 const int maxm = 5e5 + 10; 8 int n, m; 9 int unit_len;10 int be[maxn];//記錄下標L屬於哪一個分塊11 int val[maxn];12 int cnt[maxn];13 long long ans;14 long long ansa[maxn],ansb[maxn]; //答案a / b15 struct node16 {17 int l, r,id;//區間[l,r]、輸入順序18 friend bool operator<(const node&n1, const node&n2)19 {20 if (be[n1.l] == be[n2.l]) return n1.r < n2.r;21 else return n1.l < n2.l;22 }23 }qs[maxm];24 long long GCD(long long a, long long b)25 {26 if (a < b) swap(a, b);27 while (b)28 {29 long long tmp = a % b;30 a = b;31 b = tmp;32 }33 return a;34 }35 long long cal(int x)36 {37 return 1ll * x*(x - 1);38 }39 void update(int pos, int v)40 {41 ans -= cal(cnt[val[pos]]);42 cnt[val[pos]] += v;43 ans += cal(cnt[val[pos]]);44 }45 void solve()46 {47 int l = 1, r = 0;48 ans = 0;49 for (int i = 1; i <= m; i++)50 {51 int id = qs[i].id;52 while (r < qs[i].r) update(r + 1, 1), r++;53 while (r > qs[i].r) update(r, -1),r--;54 while (l < qs[i].l) update(l, -1), l++;55 while (l > qs[i].l) update(l - 1, 1), l--;56 if (ans == 0) ansa[id] = 0, ansb[id] = 1;57 else58 {59 ansb[id]= cal(qs[i].r - qs[i].l + 1);60 ansa[id]= ans;61 long long gcd = GCD(ansa[id],ansb[id]);62 ansa[id]/= gcd;63 ansb[id] /= gcd;64 }65 }66 }67 int main()68 {69 while (~scanf("%d%d", &n, &m))70 {71 unit_len = sqrt(n);72 for (int i = 1; i <= n; i++) scanf("%d", &val[i]);73 for (int i = 1; i <= n; i++) be[i] = i / unit_len + 1;74 for (int i = 1; i <= m; i++) scanf("%d%d", &qs[i].l, &qs[i].r),qs[i].id=i;75 sort(qs + 1, qs + 1 + m);76 solve();77 for (int i = 1; i <= m; i++)78 {79 printf("%lld/%lld\n", ansa[i], ansb[i]);80 }81 }82 83 84 return 0;85 }View Code
莫隊演算法