题解 P1494 【[国家集训队]小Z的袜子 /【模板】莫队】
Rainy_chen · · 题解
这里介绍一个zyb爷爷给我讲的在线做法,复杂度是和莫队相同的
我们考虑一下答案该怎么计算,令
之后显而易见的,答案就是
于是我们只需要考虑怎么快速计算出
首先对序列分块,之后我们将所有的
对于第一类的
虽然应该没有人不会这个暴力计算的方式,但是还是提一下。
我们维护当前所有颜色的出现次数,用
从块
对于第二类的
对于第三类的
显然,直接维护从块
至此,我们得到了一个需要
我分块写的不多,代码很丑qwq
#include<bits/stdc++.h>
using namespace std;
typedef long long int_t;
#ifdef ONLINE_JUDGE
#define getchar getch
#endif
char getch(){
static char B[100000], *s, *t;
return (s == t) && (t = (s = B) + fread(B, 1, 100000, stdin)), s == t ? EOF : *s++;
}
int_t read(){
int_t x=0, w=1; char C=0;
while(!isdigit(C)) {C = getchar(); if(C == '-') w = -1;}
while(isdigit(C)) x = x * 10 + C - '0', C = getchar();
return x * w;
}
int_t gcd(int_t a,int_t b){return b?gcd(b,a%b):a;}
int_t C[50010], lp[300], rp[300], bel[50010], ans[300][300], tmp[50010], cnt[300][50010];
int main() {
int_t n = read(), m = read(), siz = sqrt(n), ks = 0;
for(int_t i=1;i<=n;i++) C[i] = read(), bel[i] = (i-1) / siz + 1, rp[bel[i]] = max(rp[bel[i]], i), ks = bel[i];
for(int_t i=1;i<=ks;i++) lp[i] = rp[i-1] + 1;
for(int_t i=1;i<=ks;i++) {
for(int_t j=i,tans=0;j<=ks;j++) {
for(int_t k=lp[j];k<=rp[j];k++) tans += 2 * (++tmp[C[k]]) - 2;
ans[i][j] = tans;
}
for(int_t j=1;j<=n;j++) cnt[i][j] = cnt[i-1][j], tmp[j] = 0;
for(int_t j=lp[i];j<=rp[i];j++) cnt[i][C[j]] ++;
}
while(m--) {
int_t l = read(), r = read(), zkl = bel[l] + (l != lp[bel[l]]), zkr = bel[r] - (r != rp[bel[r]]), sdl = lp[zkl] - 1, sdr = rp[zkr] + 1, tans = ans[zkl][zkr];
if(l == r) {puts("0/1"); continue;}
if(bel[l] >= bel[r] - 1) {
tans = 0;
for(int_t i=l;i<=r;i++) tans += 2 * (++tmp[C[i]]) - 2;
for(int_t i=l;i<=r;i++) tmp[C[i]] = 0;
} else {
for(int_t i=l;i<=sdl;i++) tans += 2 * (++tmp[C[i]] + cnt[zkr][C[i]] - cnt[zkl - 1][C[i]]) - 2;
for(int_t i=sdr;i<=r;i++) tans += 2 * (++tmp[C[i]] + cnt[zkr][C[i]] - cnt[zkl - 1][C[i]]) - 2;
for(int_t i=l;i<=sdl;i++) tmp[C[i]] = 0;
for(int_t i=sdr;i<=r;i++) tmp[C[i]] = 0;
}
int_t fm = (r - l + 1) * (r - l), d = gcd(tans, fm);
printf("%lld/%lld\n", tans / d, fm / d);
}
}