Luogu P1494 [國家集訓隊]小Z的襪子

比較簡單的莫隊題,主要是爲了熟練板子。git

先考慮固定區間時咱們怎麼計算,假設區間\([l,r]\)內顏色爲\(i\)的襪子有\(cnt_i\)只,那麼對於顏色\(i\)來講,湊齊一雙的狀況個數爲:spa

  • \(cnt_i=0\)時,貢獻爲\(0\),這個咱們特別處理(顯然吧)
  • \(cnt_i>0\)時,貢獻爲\(cnt_i\cdot (cnt_i-1)\) (先挑出一隻再挑另外一隻)

最後咱們考慮全部顏色以及總狀況數,那麼此時湊出一雙機率爲:code

\[\frac{\sum cnt_i\cdot(cnt_i-1)}{(r-l+1)\cdot(r-l-2)}\]it

首先仍是考慮如何快速地轉移區間,假設咱們已經求出了\([l,r]\)的貢獻(即上式的分母部分)\(ans\),那麼咱們考慮:io

  • 推出\([l-1,r],[l,r+1]\)。假設此時加入的襪子顏色爲\(i\),那麼\(ans=ans-cnt_i\cdot(cnt_i-1)+cnt_i\cdot(cnt_i+1)\)
  • 推出\([l+1,r],[l,r-1]\)。假設此時加入的襪子顏色爲\(i\),那麼\(ans=ans-cnt_i\cdot(cnt_i-1)+(cnt_i-2)\cdot(cnt_i-1)\)

而後就能夠\(O(1)\)轉移啦,剩下的就是莫隊基本操做了class

CODEgc

#include<cstdio>
#include<cctype>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=50005;
struct data
{
    int l,r,id;
    long long ans1,ans2;
}q[N];
int n,m,L,R,a[N],cnt[N],blk[N],size;
long long res;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void write(long long x)
{
    if (x>9) write(x/10);
    putchar(x%10+'0');
}
inline bool cmp1(data a,data b)
{
    if (blk[a.l]==blk[b.l]) return blk[a.l]&1?a.r<b.r:a.r>b.r;
    return blk[a.l]<blk[b.l];
}
inline bool cmp2(data a,data b)
{
    return a.id<b.id;
}
inline void add(int col)
{
    if (++cnt[col]>=2) res+=1LL*cnt[col]*(cnt[col]-1)-1LL*(cnt[col]-1)*(cnt[col]-2);
}
inline void del(int col)
{
    if (--cnt[col]>=1) res+=1LL*cnt[col]*(cnt[col]-1)-1LL*cnt[col]*(cnt[col]+1);
}
inline long long gcd(long long n,long long m)
{
    return m?gcd(m,n%m):n;
}
inline void divnum(long long a,long long b)
{
    if (!a) { puts("0/1"); return; }
    long long d=gcd(a,b); a/=d; b/=d;
    write(a); putchar('/'); write(b); putchar('\n');
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i; read(n); read(m); size=sqrt(n);
    for (i=1;i<=n;++i) read(a[i]),blk[i]=(i-1)/size+1;
    for (i=1;i<=m;++i) read(q[i].l),read(q[i].r),q[i].id=i;
    sort(q+1,q+m+1,cmp1); L=q[1].l; R=q[1].r;
    for (i=L;i<=R;++i) add(a[i]); q[1].ans1=res; q[1].ans2=1LL*(R-L+1)*(R-L);
    for (i=2;i<=m;++i)
    {
        while (L<q[i].l) del(a[L++]); while (L>q[i].l) add(a[--L]);
        while (R>q[i].r) del(a[R--]); while (R<q[i].r) add(a[++R]);
        q[i].ans1=res; q[i].ans2=1LL*(q[i].r-q[i].l+1)*(q[i].r-q[i].l);
    }
    for (sort(q+1,q+m+1,cmp2),i=1;i<=m;++i) divnum(q[i].ans1,q[i].ans2);
    return 0;
}
相關文章
相關標籤/搜索