P1494 小Z的袜子
P1494 小Z的袜子
- 莫队板子题,对询问进行排序+分块,从而得到巧妙的复杂度
-
对于L,R的询问。
设其中颜色为x,y,z的袜子的个数为a,b,c...
那么答案即为 (a*(a-1)/2+b*(b-1)/2+c*(c-1)/2....)/((R-L+1)*(R-L)/2)(a∗(a−1)/2+b∗(b−1)/2+c∗(c−1)/2....)/((R−L+1)∗(R−L)/2)
化简得: (a^2+b^2+c^2+...x^2-(a+b+c+d+.....))/((R-L+1)*(R-L))(a2+b2+c2+...x2−(a+b+c+d+.....))/((R−L+1)∗(R−L))
即: (a^2+b^2+c^2+...x^2-(R-L+1))/((R-L+1)*(R-L))(a2+b2+c2+...x2−(R−L+1))/((R−L+1)∗(R−L))
我们需要解决的一个问题
求一个区间内每种颜色数目的平方和。
- 大佬博客
- 代码:
#include <cstdio> #include <iostream> #include <cctype> #include <algorithm> #include <cmath> using namespace std; typedef long long LL; #define res register int inline int read() { int x(0),f(1); char ch; while(!isdigit(ch=getchar())) if(ch=='-') f=-1; while(isdigit(ch)) x=x*10+ch-'0',ch=getchar(); return f*x; } const int N=50005; struct node{int x,y,z;LL p,q;}a[N]; int pos[N],c[N]; LL cnt[N]; int n,m,block; inline bool cmp1(const node &n1,const node &n2) { if(pos[n1.x]==pos[n2.x]) return n1.y<n2.y; return n1.x<n2.x; } inline bool cmp2(const node &a,const node &b) { return a.z<b.z; } inline LL gcd(LL a,LL b) { return b?gcd(b,a%b):a; } LL ans; inline void update(int i,int d) { ans-=cnt[c[i]] * cnt[c[i]]; cnt[c[i]]+=d; ans+=cnt[c[i]] * cnt[c[i]]; } inline void solve() { ans=0; int l=1,r=0; for(res i=1 ; i<=m ; ++i) { if(a[i].x==a[i].y) { a[i].p=0; a[i].q=1; continue; } for( ; r<a[i].y ; ++r) update(r+1,1); for( ; r>a[i].y ; --r) update(r,-1); for( ; l<a[i].x ; ++l) update(l,-1); for( ; l>a[i].x ; --l) update(l-1,1); LL len=a[i].y-a[i].x+1; a[i].p=ans-len; a[i].q=len*(len-1); LL tmp=gcd(a[i].p,a[i].q); a[i].p/=tmp; a[i].q/=tmp; } } int main() { n=read(); m=read(); for(res i=1 ; i<=n ; ++i) c[i]=read(); for(res i=1 ; i<=m ; ++i) a[i].x=read(),a[i].y=read(),a[i].z=i; block = sqrt(n); for(res i=1 ; i<=n ; ++i) pos[i]=(i-1)/block+1; sort(a+1,a+m+1,cmp1); solve(); sort(a+1,a+m+1,cmp2); for(res i=1 ; i<=m ; ++i) printf("%lld/%lld\n",a[i].p,a[i].q); return 0; }