1. 程式人生 > 其它 >莫隊——[國家集訓隊]小Z的襪子

莫隊——[國家集訓隊]小Z的襪子

技術標籤:演算法# 莫隊

題目連結

題目描述

作為一個生活散漫的人,小 Z 每天早上都要耗費很久從一堆五顏六色的襪子中找出一雙來穿。終於有一天,小 Z 再也無法忍受這惱人的找襪子過程,於是他決定聽天由命……

具體來說,小 Z 把這 N 只襪子從 1 到 N 編號,然後從編號 L 到 R (L 儘管小 Z 並不在意兩隻襪子是不是完整的一雙,甚至不在意兩隻襪子是否一左一右,他卻很在意襪子的顏色,畢竟穿兩隻不同色的襪子會很尷尬。

你的任務便是告訴小 Z,他有多大的概率抽到兩隻顏色相同的襪子。當然,小 Z 希望這個概率儘量高,所以他可能會詢問多個 (L,R) 以方便自己選擇。

然而資料中有 L=R 的情況,請特判這種情況,輸出0/1。

輸入格式

輸入檔案第一行包含兩個正整數 N 和 M。N 為襪子的數量,M 為小 Z 所提的詢問的數量。接下來一行包含 N 個正整數 Ci,其中 Ci 表示第 i 只襪子的顏色,相同的顏色用相同的數字表示。再接下來 M 行,每行兩個正整數 L, R 表示一個詢問。

輸出格式

包含 M 行,對於每個詢問在一行中輸出分數 A/B 表示從該詢問的區間 [L,R] 中隨機抽出兩隻襪子顏色相同的概率。若該概率為 0 則輸出 0/1,否則輸出的 A/B 必須為最簡分數。(詳見樣例)

輸入輸出樣例

輸入

6 4
1 2 3 3 3 2
2 6
1 3
3 5
1 6

輸出

2/5
0/1
1/1
4/15

說明/提示

30%的資料中,N,M ≤ 5000;

60%的資料中,N,M ≤ 25000;
100%的資料中,N,M ≤ 50000,1 ≤ L < R ≤ N,Ci ≤ N。

分析

設不同顏色的襪子個數分別為 a,b,c…,然後我們就可以推出
在這裡插入圖片描述
從這個公式中,我們可以看出最後的結果都和不同顏色的襪子個數的平方和有關,那麼我們在新增或者刪除的時候,都要考慮一下新增或刪除的某種襪子的個數的平方和的變化,而每次查詢的 L,R 是固定的,因此,可以在考慮完平方和問題之後再對分子分母進行相關操作,然後再求出分子分母的最大公約數,化簡即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn =
1e6 + 10; int n, m, L, R; long long sum; int a[maxn], f[maxn], cnt[maxn]; long long ans1[maxn], ans2[maxn]; struct node{ int l, r, id; }q[maxn]; bool cmp(node x,node y){ return f[x.l] ^ f[y.l] ? f[x.l] < f[y.l] : ((f[x.l] & 1) ? x.r < y.r : x.r > y.r); } int main() { scanf("%d%d", &n, &m); 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; } int unit = sqrt(n); for(int i = 1; i <= n; i++){ f[i] = i / unit + 1; } sort(q + 1, q + m + 1, cmp); L = q[1].l, R = q[1].l - 1; sum = 0; for(int i = 1; i <= m; i++){ while(L < q[i].l){ sum -= cnt[a[L]] * cnt[a[L]]; cnt[a[L]]--; sum += cnt[a[L]] * cnt[a[L]]; L++; } while(L > q[i].l){ L--; sum -= cnt[a[L]] * cnt[a[L]]; cnt[a[L]]++; sum += cnt[a[L]] * cnt[a[L]]; } while(R < q[i].r){ R++; sum -= cnt[a[R]] * cnt[a[R]]; cnt[a[R]]++; sum += cnt[a[R]] * cnt[a[R]]; } while(R > q[i].r){ sum -= cnt[a[R]] * cnt[a[R]]; cnt[a[R]]--; sum += cnt[a[R]] * cnt[a[R]]; R--; } if(q[i].l == q[i].r){ ans1[q[i].id] = 0; ans2[q[i].id] = 1; continue; } ans1[q[i].id] = sum - (q[i].r - q[i].l + 1); ans2[q[i].id] = 1LL * (q[i].r - q[i].l + 1) * (q[i].r - q[i].l); long long g = __gcd(ans1[q[i].id], ans2[q[i].id]); ans1[q[i].id] /= g; ans2[q[i].id] /= g; } for(int i = 1; i <= m; i++){ if(ans1[i] == 0){ printf("0/1\n"); } else{ printf("%lld/%lld\n", ans1[i], ans2[i]); } } return 0; }