P1494 Socks of Little Z [National Training Team]
Label
Preface
Concise title
- Probability of Selecting Two Equal Numbers from Query Interval [L,R]
thinking
- Mo team is very good at playing, the difficulty is how to update the probability after the pointer moves.
- Let cnt [] be the number of occurrences of each number in the current interval, and l, r represent the endpoint of the current interval, so the answer to this interval should be:
\[\frac{\sum\limits_{x(cnt[x>=2])} C_{cnt[x]}^{2}}{C_{r-l+1}^{2}}\]
- (Next omit CNT [x]>= 2) Break down the number of combinations:
\[\frac{\sum\limits_{x}( cnt[x](cnt[x]-1)}{(r-l+1)(r-l)}\]
- It is found that the molecule is better handled. First, the original contribution of cnt[x] is subtracted, and then the new contribution is added. Now the problem lies in the denominator treatment.
\[(r-l+1)(r-l)\]
- Actually, ducks are also handled very well. Think of R-L as a whole, and then it's very simple. Then we should open one more variable to maintain the value of r-l. That's all.
Matters needing attention
summary
- Initially l=1, r=0, then the initial r-l should be -1
AC code
#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 5e4 + 10;
long long gcd(long long a, long long b)
{
if (b == 0) return a;
return gcd(b, a % b);
}
struct Query
{
int l, r, id, k;
bool operator <(const Query& a)const
{
if (k == a.k)
return r < a.r;
return k < a.k;
}
};
Query query[maxn];
int n, q, a[maxn];
long long cnt[maxn];
long long mu = 0, zi = 0, r_l = -1;
void add(int x)
{
x = a[x];
mu += 2 * r_l + 2, r_l++;
zi -= cnt[x] * cnt[x] - cnt[x];
cnt[x]++;
zi += cnt[x] * cnt[x] - cnt[x];
}
void remove(int x)
{
x = a[x];
mu -= 2 * r_l, r_l--;
zi -= cnt[x] * cnt[x] - cnt[x];
cnt[x]--;
zi += cnt[x] * cnt[x] - cnt[x];
}
pair<long long, long long> ans0[maxn];
void solve()
{
scanf("%d%d", &n, &q);
int len = sqrt(n / 2 * 3);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (int i = 1; i <= q; i++)
scanf("%d%d", &query[i].l, &query[i].r), query[i].id = i, query[i].k = (query[i].l - 1) / len + 1;
sort(query + 1, query + 1 + q);
int l = 1, r = 0;
for (int i = 1; i <= q; i++)
{
int L = query[i].l, R = query[i].r, id = query[i].id;
while (l < L) remove(l++);
while (l > L) add(--l);
while (r < R) add(++r);
while (r > R) remove(r--);
if (zi == 0 || L == R) ans0[id].first = 0, ans0[id].second = 1;
else
{
long long t = gcd(zi, mu);
ans0[id].first = zi / t, ans0[id].second = mu / t;
}
}
for (int i = 1; i <= q; i++)
printf("%lld/%lld\n", ans0[i].first, ans0[i].second);
}
int main()
{
freopen("Testin.txt", "r", stdin);
solve();
return 0;
}