BZOJ 2038 小z的袜子(莫队入门)
题意:不多介绍了
思路:我们对于每个ans的计算,分子等于区间内每种每种颜色的平方加和,分母是区间长度的平方,对于l向右修改一次,我们相当于减去那种颜色的一个次数,我们可以先减去原来的ans,然后再修改区间的值,然后再加上修改后的值,打给莫队算法就是这样,然后理工分块,以及排序的思想,降低了复杂度。
(chaoxi)代码:
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; #define N 50001 #define LL long long int n,m,num[N],c[N]; LL pre[N],ans; LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);} LL sqr(LL x){return x*x;} struct node { int l,r,id; LL a,b; }a[N]; bool cmp(node a,node b) { if(num[a.l]==num[b.l]) return a.r<b.r; return a.l<b.l; } bool cmp_id(node a,node b) { return a.id<b.id; } void update(int p,int val) { ans-=sqr(pre[c[p]]); pre[c[p]]+=val; ans+=sqr(pre[c[p]]); } void solve() { for(int i=1,l=1,r=0;i<=m;i++){ for(;r<a[i].r;r++) update(r+1,1); for(;r>a[i].r;r--) update(r,-1); for(;l<a[i].l;l++) update(l,-1); for(;l>a[i].l;l--) update(l-1,1); if(a[i].l==a[i].r){ a[i].a=0,a[i].b=1; continue; } a[i].a=ans-(a[i].r-a[i].l+1); a[i].b=(LL)(a[i].r-a[i].l+1)*(a[i].r-a[i].l); LL k=gcd(a[i].a,a[i].b); a[i].a/=k;a[i].b/=k; } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&c[i]); int block=int(sqrt(n)); for(int i=1;i<=n;i++) num[i]=(i-1)/block+1; for(int i=1;i<=m;i++){ scanf("%d%d",&a[i].l,&a[i].r); a[i].id=i; } sort(a+1,a+1+m,cmp); solve(); sort(a+1,a+1+m,cmp_id); for(int i=1;i<=m;i++){ printf("%lld/%lld\n",a[i].a,a[i].b); } return 0; }