P1494 [国家集训队]小Z的袜子 (莫队)

离线莫队

 题目链接

[L,R]区间内:

设每种袜子的数量分别为:a,b,c...

则答案为:(a * (a-1) + b * (b - 1) + c * (c - 1) + ...) / ((R - L + 1) * (R - L))

化简即为:(a * a + b * b + c * c + ... - (R - L + 1)) / ((R - L + 1) * (R - L))

所以我们求:((\sum a^2) - (R-L+1))/(R-L+1)*(R-L)即可

 

#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;
}
View Code

 

posted @ 2019-05-26 18:53  html_11  阅读(128)  评论(0编辑  收藏  举报