P1494 [国家集训队]小Z的袜子 (莫队)
离线莫队
[L,R]区间内:
设每种袜子的数量分别为:
则答案为:
化简即为:
所以我们求:即可
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <map> #include <set> #include <vector> #include <string> #include <cmath> #define rep(i, s, e) for(int i = s; i < e; ++i) #define P pair<int, int> #define INF 0x3f3f3f3f using namespace std; typedef long long ll; static const int MAX_N = 5e4 + 5; static const ll Mod = 1e9 + 7; struct Query{ int l, r, id, pos; bool operator < (Query &q)const{ if(pos == q.pos) return r < q.r; return pos < q.pos; } }q[MAX_N]; struct Answer{ ll rev1, rev2; }rev[MAX_N]; int cnt[MAX_N], a[MAX_N]; ll gcd(ll x, ll y){ return y == 0 ? x : gcd(y, x % y); } ll ans; //这里会卡个long long void update(int p, int v){ ans -= cnt[a[p]] * cnt[a[p]]; cnt[a[p]] += v; ans += cnt[a[p]] * cnt[a[p]]; } void solve(){ int n, m; scanf("%d%d", &n, &m); int block = (int)sqrt(n); for(int i = 1; i <= n; ++i) scanf("%d", &a[i]); for(int i = 1; i <= m; ++i){ scanf("%d%d", &q[i].l, &q[i].r); q[i].id = i; q[i].pos = (q[i].l - 1) / block + 1; } sort(q + 1, q + m + 1); int l = 1, r = 0; for(int i = 1; i <= m; ++i){ if(q[i].l == q[i].r){ rev[q[i].id].rev1 = 0; rev[q[i].id].rev2 = 1; continue; } while(l < q[i].l) update(l++, -1); while(l > q[i].l) update(--l, 1); while(r < q[i].r) update(++r, 1); while(r > q[i].r) update(r--, -1); int le = q[i].r - q[i].l + 1; rev[q[i].id].rev1 = ans - le; rev[q[i].id].rev2 = (ll)le * (le - 1); ll gc = gcd(rev[q[i].id].rev1, rev[q[i].id].rev2); rev[q[i].id].rev1 /= gc; rev[q[i].id].rev2 /= gc; } for(int i = 1; i <= m; ++i) printf("%lld/%lld\n", rev[i].rev1, rev[i].rev2); } int main() { // freopen("input.txt", "r", stdin); // freopen("output.txt", "w", stdout); solve(); return 0; }