2038: [2009国家集训队]小Z的袜子(hose)

来源:互联网 发布:阿里云学生机怎么买 编辑:程序博客网 时间:2024/06/11 20:29
听说这个算法叫莫队。
若一个区间[l,r]所有颜色的袜子总数cnt[i]已预处理好,我们可以直接求出答案:∑(cnt[i]-1)*cnt[i]/((r-l+1)*(r-l))
经观察,我们知道区间[l-1,r]、[l+1,r]、[l,r-1]、[l,r+1]均可O(1)求得。
考虑分块,将所有坐标分成sqrt(n)个区间,然后对询问离线后进行排序,第一关键字为左端点所在区间编号,第二关键字为右端点大小。
然后从左往右暴力统计就可以了,感性理解可知,时间复杂度为O(nsqrt(n))。
#include<cstdio>#include<iostream>#include<algorithm>#include<queue>#include<cstdlib>#include<cmath>using namespace std;#define rep(i,j,k) for(i=j;i<=k;++i)#define per(i,j,k) for(i=j;i>=k;--i)#define ll long long#define db double#define ldb long double#define pll pair<ll,ll>#define mkp make_pair#define X first#define Y secondconst int N=50005;struct QUERY{ll L,R,flg;}qu[N];ll n,m,s,a[N],md[N];ll cnt[N];pll ans[N];bool cmp(QUERY x,QUERY y){return md[x.L]==md[y.L]?x.R<y.R:x.L<y.L;}ll gcd(ll x,ll y){ll z=x%y;return z?gcd(y,z):y;}int main(){ll i,j,x,y,u,v;ll S;scanf("%lld%lld",&n,&m);s=(int)sqrt(n);x=1;rep(i,1,n){scanf("%lld",&a[i]);md[i]=x;x+=i%s==0;}rep(i,1,m){scanf("%lld%lld",&x,&y);qu[i]=(QUERY){x,y,i};}sort(qu+1,qu+m+1,cmp);x=qu[1].L,y=qu[1].R;rep(i,x,y)++cnt[a[i]];S=0;rep(i,1,n)S+=cnt[i]*(cnt[i]-1);ans[qu[1].flg]=mkp(S,(y-x+1)*(y-x));rep(i,2,m){u=qu[i].L,v=qu[i].R;if(v>y)rep(j,y+1,v)S+=cnt[a[j]]++<<1;else per(j,y,v+1)S-=--cnt[a[j]]<<1;if(u<x)per(j,x-1,u)S+=cnt[a[j]]++<<1;else rep(j,x,u-1)S-=--cnt[a[j]]<<1;x=u,y=v;ans[qu[i].flg]=mkp(S,(y-x+1)*(y-x));}rep(i,1,m){if(!ans[i].X)puts("0/1");else{x=gcd(ans[i].X,ans[i].Y);printf("%lld/%lld\n",ans[i].X/x,ans[i].Y/x);}}return 0;}



0 0
原创粉丝点击