题意:取一段区间,求区间中任取两个数相同的概率;
思路:所求概率P=(A*(A-1)/2+B*(B-1)/2+......)/(R-L+1)*(R-L)/2化简得P=(A*A+B*B+......+Z*Z-(R-L+1))/(R-L+1)*(R-L);
将询问区间左端点放在同一分块中处理,每次处理一个块中的所有询问,对于同一块,询问右端点按严格递增处理,左端点不断移动;
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; int t,n,m,unit; int a[500010],num[500010]; struct node { int id,L,R; }M[500010]; int cmp(node a,node b) { if(a.L/unit!=b.L/unit) return a.L/unit<b.L/unit; return a.R<b.R; } long long gcd(long long a,long long b) { if(b==0) return a; return gcd(b,a%b); } struct que { long long a,b; void reduce() //分数约分 { long long d=gcd(a,b); a/=d;b/=d; } }ans[500010]; void work() { int L=1,R=0; long long temp=0; memset(num,0,sizeof(num)); //区间中同种数的个数 for(int i=0;i<m;i++) { while(R<M[i].R) { R++; temp-=(long long)num[a[R]]*num[a[R]]; num[a[R]]++;//a[R]的个数加1 temp+=(long long)num[a[R]]*num[a[R]]; } while(L>M[i].L) { L--; temp-=(long long)num[a[L]]*num[a[L]]; num[a[L]]++;//a[L]的个数加1 temp+=(long long)num[a[L]]*num[a[L]]; } while(R>M[i].R) { temp-=(long long)num[a[R]]*num[a[R]]; num[a[R]]--;//a[L]的个数减1 temp+=(long long)num[a[R]]*num[a[R]]; R--; } while(L<M[i].L) { temp-=(long long)num[a[L]]*num[a[L]]; num[a[L]]--;//a[R]的个数减1 temp+=(long long)num[a[L]]*num[a[L]]; L++; } ans[M[i].id].a=temp-(R-L+1); ans[M[i].id].b=(long long)(R-L)*(R-L+1); ans[M[i].id].reduce(); } } int main() { int i,j,k; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;i++) scanf("%d",&a[i]); unit=(int)sqrt(n); //总区间分为unit块 for(i=0;i<m;i++) { M[i].id=i; scanf("%d%d",&M[i].L,&M[i].R); } sort(M,M+m,cmp); //对询问排序 work(); for(i=0;i<m;i++) printf("%lld/%lld\n",ans[i].a,ans[i].b); } return 0; }
时间: 2024-11-13 22:43:14