洛谷 #1494. 小Z的袜子

题意

问在l~r区间内拿到两只一样颜色袜子的概率(要化简)

题解

概率 = ∑ i = 1 v ( 2 c n t i ) ( 2 l e n ) \frac{\sum_{i=1}^{v}\binom{2}{cnt_i}}{\binom{2}{len}} (len2)i=1v(cnti2)
化简 = ∑ i = 1 v c n t i 2 − l e n l e n ( l e n − 1 ) \frac{\sum_{i=1}^{v}cnt_i^2-len}{len(len-1)} len(len1)i=1vcnti2len
莫队维护 \(\ cnt_i^2\) 即可

调试记录

l指针和r指针的更新是相反的
#include <cstdio>
#include <cmath>
#include <algorithm>
#define maxn 50005
#define int long long

using namespace std;

struct node{
    int l, r, id, a, b;
}q[maxn];

int n, m, a[maxn], cnt[maxn], pos[maxn];
int sqr(int x){ return x * x; }

bool cmp(node a, node b){
    if (pos[a.l] == pos[b.l]) return a.r < b.r;
    return a.l < b.l;
}

bool idcmp(node a, node b){ return a.id < b.id; }

int gcd(int x, int y){
    if (!y) return x;
    return gcd(y, x % y);
}

void solve(){
    int r = 0, l = 1, ans = 0;
    for (int i = 1; i <= m; i++){
        for (; r < q[i].r; r++) ans -= sqr(cnt[a[r + 1]]), cnt[a[r + 1]]++, ans += sqr(cnt[a[r + 1]]);
        for (; r > q[i].r; r--) ans -= sqr(cnt[a[r]]), cnt[a[r]]--, ans += sqr(cnt[a[r]]);
        for (; l < q[i].l; l++) ans -= sqr(cnt[a[l]]), cnt[a[l]]--, ans += sqr(cnt[a[l]]);
        for (; l > q[i].l; l--) ans -= sqr(cnt[a[l - 1]]), cnt[a[l - 1]]++, ans += sqr(cnt[a[l - 1]]);
        
        if (q[i].l == q[i].r){
            q[i].a = 0; q[i].b = 1;
            continue;
        }
        
//		printf("%d~%d len = %d ^sum = %d\n", q[i].l, q[i].r, q[i].r - q[i].l + 1, ans);
        q[i].a = ans - (q[i].r - q[i].l + 1);
        q[i].b = (q[i].r - q[i].l + 1) * (q[i].r - q[i].l);
//		printf("a = %d b = %d\n", q[i].a, q[i].b);
        
        int tmp = gcd(q[i].a, q[i].b);
        q[i].a /= tmp; q[i].b /= tmp;	
    }
}

signed main(){
    scanf("%lld%lld", &n, &m);
    
    for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    int block = sqrt(m);
    for (int i = 1; i <= m; i++)
        pos[i] = (i - 1) / block + 1;
    
    for (int i = 1; i <= m; i++){
        scanf("%lld%lld", &q[i].l, &q[i].r);
        q[i].id = i;
    }
    sort(q + 1, q + m + 1, cmp);
    solve();
    sort(q + 1, q + m + 1, idcmp);
    for (int i = 1; i <= m; i++)
        printf("%lld/%lld\n", q[i].a, q[i].b);
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值