莫队算法 BOJ 2038 [2009国家集训队]小Z的袜子(hose)

 

题目传送门

 1 /*  2  莫队算法:求出[l, r]上取出两只相同袜子的个数。  3  莫队算法是离线处理一类区间不修改查询类问题的算法。如果你知道了[L,R]的答案,可以在O(1)的时间下得到  4  [L,R-1]和[L,R+1]和[L-1,R]和[L+1,R],4个while是精华!  5  对于莫队算法我感觉就是暴力。只是预先知道了所有的询问。可以合理的组织计算每个询问的顺序以此来降低复杂度。  6  详细解释:http://blog.csdn.net/bossup/article/details/39236275  7 */  8 #include <cstdio>  9 #include <cstring> 10 #include <algorithm> 11 #include <cmath> 12 using namespace std; 13 14 typedef long long ll; 15 const int MAXN = 5e4 + 10; 16 const int INF = 0x3f3f3f3f; 17 struct Data 18 { 19 int b, l, r, id; 20  ll x, y; 21  Data () {} 22 Data (int b, ll l, ll r, int id) : b (b), l (l), r (r), id (id) {}; 23 }data[MAXN]; 24 int cnt[MAXN]; 25 int a[MAXN]; 26 int n, m; 27 ll ans; 28 29 bool cmp_pre(Data x, Data y) 30 { 31 if (x.b == y.b) return x.r < y.r; 32 return x.b < y.b; 33 } 34 35 bool cmp_id(Data x, Data y) {return x.id < y.id;} 36 37 ll cal(int v) {return (ll) v * v;} 38 39 void updata(int v, int add) 40 { 41 ans -= cal (cnt[v]); 42 cnt[v] += add; 43 ans += cal (cnt[v]); 44 } 45 46 ll GCD(ll a, ll b) {return b == 0 ? a : GCD (b, a % b);} 47 48 void Modui(void) 49 { 50 sort (data+1, data+1+m, cmp_pre); 51 memset (cnt, 0, sizeof (cnt)); 52 53 int l = 1, r = 0; ans = 0; 54 for (int i=1; i<=m; ++i) 55  { 56 while (data[i].l < l) updata (a[--l], 1); 57 while (data[i].l > l) updata (a[l], -1), l++; 58 while (data[i].r > r) updata (a[++r], 1); 59 while (data[i].r < r) updata (a[r], -1), r--; 60 61 if (data[i].l == data[i].r) 62  { 63 data[i].x = 0; data[i].y = 1; 64 continue; 65  } 66 data[i].x = ans - (data[i].r - data[i].l + 1); 67 data[i].y = (ll) (data[i].r - data[i].l + 1) * (data[i].r - data[i].l); 68 ll k = GCD (data[i].x, data[i].y); 69 data[i].x /= k; data[i].y /= k; 70  } 71 72 sort (data+1, data+1+m, cmp_id); 73 for (int i=1; i<=m; ++i) 74  { 75 printf ("%lld/%lld\n", data[i].x, data[i].y); 76  } 77 } 78 79 int main(void) //BOJ 2038 [2009国家集训队]小Z的袜子(hose) 80 { 81 // freopen ("BZOJ_2038.in", "r", stdin); 82 83 while (scanf ("%d%d", &n, &m) == 2) 84  { 85 for (int i=1; i<=n; ++i) scanf ("%d", &a[i]); 86 87 int block = (int) sqrt (n * 1.0); 88 for (int i=1; i<=m; ++i) 89  { 90 int l, r; 91 scanf ("%d%d", &l, &r); 92 data[i] = Data (l / block, l, r, i); 93  } 94 95  Modui (); 96  } 97 98 return 0; 99 }

 

你可能感兴趣的:(算法)