您的位置:首页 > 其它

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

2017-02-11 21:37 357 查看
我可以用我基本靠蒙的数学功底来推一下式子,求一个分数,分子是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
,cnt
,sum,ans2
;
int blo,a
;
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
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: