洛谷 P1494 [国家集训队]小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必須為最簡分數。(詳見樣例)
?
輸入輸出樣例
輸入樣例#1:?復制 6 4 1 2 3 3 3 2 2 6 1 3 3 5 1 6 輸出樣例#1:?復制 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。
?
莫隊算法入門是在大米餅的博客學習的 戳這里%%%
這道題之前在東北講莫隊的時候講過 然后今天大家都在搞這道題 我就來湊個熱鬧
很明顯這道題$O(n√n)$是可以過得?
根據莫隊算法的基本思想 離線處理詢問 現將詢問按照左端點分組 在同一個塊內的分成一組 然后再對每個塊內的詢問按照右端點排序
接社我們處理完一個詢問 那么到達下一個同組內的詢問時 左端點在同一個塊內反復橫跳 右端點遞增的掃過去 就利用了之前的信息?
現在就是怎么算答案了 設每個顏色的數量分別為?$a1,a2,a3,a4 .... $
那么每個顏色被選中的情況的數量
化簡得
? ? ? ? ?$(a1 * (a1 - 1) + a2 * (a2 - 1) + ... )\cdot \frac{1}{2}= \sum_{i = 1}^{n} (ai\cdot ai - ai)\cdot \frac{1}{2} = (\sum_{i = 1}^{n}ai\cdot ai - len)\cdot \frac{1}{2}$
$len$是詢問區間長度 即$R - L+1$
概率就是 上面那一坨再除以$_{len}^{2}\textrm{C}$?
再化化簡得 $\frac{\sum_{i= 1}^{n} ai^{2} - len}{(len - 1)\cdot len}$
所以對于這玩意我們只需要維護每種顏色的平方和 剩下的就是各種細節亂搞了
代碼
#include <bits/stdc++.h> using namespace std;typedef long long ll; const int N = 5 * 1e5 + 5; int n,m,num[800],c[N],blo,cnt; ll h[N],ans;struct ques {int l,r,id; }q[N],k[800][800],a[N];bool cmp(const ques & a,const ques & b) {return a.r < b.r; }void Init( ) {scanf("%d%d",& n,& m);for(int i = 1;i <= n;i ++) scanf("%d",& c[i]);blo = sqrt(n);for(int i = 1;i <= m;i ++) {scanf("%d%d",& q[i].l,& q[i].r);q[i].id = i;int b = (q[i].l + blo - 1) / blo;k[b][++ num[b]] = q[i];}cnt = (n + blo - 1) / blo;for(int i = 1;i <= cnt;i ++) if(num[i]) sort(k[i],k[i] + num[i] + 1,cmp);int tot = 0;for(int i = 1;i <= cnt;i ++)if(num[i]) {for(int j = 1;j <= num[i];j ++)q[++ tot] = k[i][j];} }ll gcd(ll a,ll b) {return b == 0 ? a : gcd(b,a % b); }void update(int pos,int del) {ans -= h[c[pos]] * h[c[pos]];h[c[pos]] += del;ans += h[c[pos]] * h[c[pos]]; }void Solve( ) {ans = 0;int L,R,las = 0;for(int i = 1;i <= m;i ++) {int now = (q[i].l + blo - 1) / blo;if(i == 1) {las = now;if(q[i].l == q[i].r) {printf("0/1\n"); L = q[i].l; R = q[i].r;continue;}for(int j = q[i].l;j <= q[i].r;j ++) h[c[j]] ++;for(int j = 0;j <= n;j ++) {ans += (h[j] * h[j]);}L = q[i].l; R = q[i].r;}else {for(;R < q[i].r;R ++) update(R + 1,1);for(;R > q[i].r;R --) update(R,-1);for(;L > q[i].l;L --) update(L - 1,1);for(;L < q[i].l;L ++) update(L,-1);}if(q[i].l == q[i].r) {a[q[i].id].l = 0; a[q[i].id].r = 1;continue;} ll len = q[i].r - q[i].l + 1;ll u = len * (len - 1),g = gcd(ans - len,u);ll up = (ans - len) / g;ll down = u / g;a[q[i].id].l = up; a[q[i].id].r = down;}for(int i = 1;i <= m;i ++) printf("%d/%d\n",a[i].l,a[i].r); }int main( ) {Init( );Solve( ); }轉載于:https://www.cnblogs.com/Rubenisveryhandsome/p/9645782.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的洛谷 P1494 [国家集训队]小Z的袜子的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IOS-网络(监听网络状态)
- 下一篇: php递归操作目录 递归对参数转义