题目描述
小B有一个序列,包含N个1~K之间的整数。他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数。小B请你帮助他回答询问。
输入输出格式
输入格式:
第一行,三个整数N、M、K。
第二行,N个整数,表示小B的序列。
接下来的M行,每行两个整数L、R。
输出格式:
M行,每行一个整数,其中第i行的整数表示第i个询问的答案。
输入输出样例
说明
对于全部的数据,1<=N、M、K<=50000
题解;
k^2和(k+1)^2的关系。
#include <bits/stdc++.h> using namespace std; const int MAXN=50010; int a[MAXN],num[MAXN],s,ans=0,anss[MAXN]; struct node{ int l,r; int id; }x[MAXN]; bool cmp1(node k,node z) { if(k.l/s==z.l/s) //此处时分块的地方,将在同一块的放在一起。 { return k.r<z.r; } return k.l<z.l; } void add(int i) { int k=num[a[i]]++;//(k+1)^2-k^2=2*k+1;从k->k+1加上2*k+1; ans+=k*2+1; } void del(int i) { int k=--num[a[i]];//此处便是减去前一个的2*k+1; ans=ans-2*k-1; } int main() { int n,m,k; scanf("%d%d%d",&n,&m,&k); for (int i = 1; i <=n ; ++i) { scanf("%d",&a[i]); } s=(int)sqrt(n); for (int i = 1; i <=m ; ++i) { scanf("%d%d",&x[i].l,&x[i].r); x[i].id=i; } sort(x+1,x+1+m,cmp1); int l=1,r=0; ans=0; for (int i = 1; i <=m ; ++i) { while (r<x[i].r) add(++r); //r本身已经加过了,要从下一点开始。 while (r>x[i].r) del(r--);//减这个操作要把自己本身也给减掉。 while (l>x[i].l) add(--l); while (l<x[i].l) del(l++); anss[x[i].id]=ans; } for (int i = 1; i <=m ; ++i) { printf("%d ",anss[i]); } return 0; }