【bzoj2038】 [2009国家集训队]小Z的袜子(hose)

我可以用我基本靠蒙的数学功底来推一下式子,求一个分数,分子是sigma(1,i)C(2,i);分母是C(2,r-l+1),又因为C(2,n)=(x^2-x)/2,对于分母是可以O(1)计算的,所以我们只记录分子就可以,对于分子我们可以发现左右端点是可以递推出来的,如果a[R+1]为q则我们在由R到R+1唯一改变的值是C(2,sum[q])
C(2,sum[q])=(sum[q]^2-sum[q])/2;———-(1)
C(2,sum[q]+1)=((sum[q]+1)^2-(sum[q]+1));—–(2)
(2)式-(1)式得
(2)-(1)=2sum[q]
递推R-1,L+1,L-1的时候同理,所以我们可以用莫队算法来做这道题
然后另外一个问题是对于莫队算法分块的大小问题上一篇博客没提,莫队的分块大小其实并不是很严谨,在sqrt(N),sqrt(M),N/sqrt(M)左右都是可以的

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>

using namespace std;
const int N=50010;
typedef long long ll;
ll ans[N],cnt[N],sum,ans2[N];
int blo,a[N];
inline int F()
{
    register int aa,bb;register char ch;
    while (ch=getchar(),(ch<'0'||ch>'9')&&ch!='-');ch=='='?aa=bb=0:(aa=ch-'0',bb=1);
    while (ch=getchar(),ch>='0'&&ch<='9')aa=(aa<<3)+(aa<<1)+ch-'0';return bb?aa:-aa;
}
struct query{
    int l,r,id,lb;
    bool operator <(const query &rhs)const{
        return lb==rhs.lb? r<rhs.r:lb<rhs.lb; 
    }
}q[N]; 
inline ll gcd(ll a,ll b)
{
    for (;a&&b;swap(a,b)){
        a%=b;
    }
    return a|b;
}
int main()
{
//  freopen("std.in","r",stdin);
    memset(cnt,0,sizeof(cnt));
    int n,m,l,r;
    n=F(),m=F();
    blo=sqrt(n);
    for (int i=1;i<=n;i++)
    a[i]=F();
    for (int i=1;i<=m;i++)
    q[i].id=i,q[i].l=F(),q[i].r=F(),q[i].lb=q[i].l/blo;
    sort(q+1,q+m+1);
    int nowl=1,nowr=0;
    ll sum=0;
    for (int i=1;i<=m;i++)
    {
        while (nowr<q[i].r)sum+=cnt[a[++nowr]]++;
        while (nowl>q[i].l)sum+=cnt[a[--nowl]]++;
        while (nowr>q[i].r)sum-=(--cnt[a[nowr--]]);
        while (nowl<q[i].l)sum-=(--cnt[a[nowl++]]); 
        ll g=gcd(sum,1ll*(nowr-nowl+1)*(nowr-nowl)/2);
        ans[q[i].id]=sum/g;
//      cout<<ans[q[i].id]<<' '<<sum<<' '<<g<<' '<<nowl<<' '<<nowr<<endl;
        ans2[q[i].id]=1ll*(nowr-nowl+1)*(nowr-nowl)/2/g;
    } 
    for (int i=1;i<=m;i++)
    printf("%lld/%lld\n",ans[i],ans2[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值