Random Query CodeForces - 846F
翻译:
给出一个n个数字的数列a[1],...,a[n],f(l,r)表示使a[l],a[l+1],...,a[r]组成的新序列中的重复元素只保留一个后,剩下元素的数量(如果l>r,则在计算前先交换l和r)。从1-n中分别选出两个数字l和r(两个数字选时各自独立,每个数字选出1-n的概率相等),求f(l,r)的数学期望。
就是$\dfrac {\sum _{l\leq n}^{l=1}\sum _{r\leq n}^{r=1}f\left( l,r\right) } {n^{2}}$
然后,我参照这道题的做法写了一个O(log(n)*n^2)
1 #include<cstdio> 2 typedef long long LL; 3 LL c[1001000]; 4 LL n,ans; 5 LL a[1001000]; 6 LL next1[1001000]; 7 LL boo[1001000]; 8 LL lowbit(LL x) 9 { 10 return x&-x; 11 } 12 void add(LL num,LL x) 13 { 14 while(num<=n) 15 { 16 c[num]+=x; 17 num+=lowbit(num); 18 } 19 } 20 LL sum1(LL x) 21 { 22 LL ans=0; 23 while(x>0) 24 { 25 ans+=c[x]; 26 x-=lowbit(x); 27 } 28 return ans; 29 } 30 LL sum(LL l,LL r) 31 { 32 return sum1(r)-sum1(l-1); 33 } 34 int main() 35 { 36 LL i,j; 37 scanf("%lld",&n); 38 for(i=1;i<=n;i++) 39 scanf("%lld",&a[i]); 40 for(i=n;i>=1;i--) 41 next1[i]=boo[a[i]],boo[a[i]]=i; 42 //boo[i]记录数字i第一次出现位置,next1[i]记录第i个数字下一次出现位置 43 for(i=1;i<=n;i++) 44 if(boo[a[i]]==i) 45 add(i,1); 46 for(i=1;i<=n;i++) 47 { 48 for(j=i+1;j<=n;j++) 49 ans+=sum(i,j); 50 if(next1[i]!=0) 51 add(next1[i],1); 52 } 53 ans*=2; 54 ans+=n; 55 printf("%lf",(double)ans/(double)n/(double)n); 56 return 0; 57 }
然后,就tle了。。。
经过大佬的指点后,我打开了新世界的大门找到了新的方法
例如:1 2 2 2 3
第1个2对1-2,1-3,1-4,1-5,2-2,2-3,2-4,2-5的不相同值的数量有贡献
第2个2对3-3,3-4,3-5的不相同值的数量有贡献
第3个2对4-4,4-5的不相同的值的数量有贡献
由于每一组a-b,b-a(a<b)只计算了其中的一个(a-b),所以要乘2。
由于乘2后所有a-a计算2遍,所以要减去n。
1 #include<cstdio> 2 typedef long long LL; 3 //bool exist[1001000]; 4 int last[1001000]; 5 LL ans,n; 6 int main() 7 { 8 LL i,t; 9 scanf("%lld",&n); 10 for(i=1;i<=n;i++) 11 { 12 scanf("%lld",&t); 13 ans+=(i-last[t])*(n-i+1); 14 last[t]=i; 15 //(last[t]+1)-i,..,(last[t]+1)-n,.....,i-i,..,i-n 16 //last[t]+1:n-i+1;...i:n-i+1 17 // if(exist[t]) 18 // ans+=n-i+1; 19 // else 20 // { 21 // exist[t]=true; 22 // //ans+=i*(n-i+1); 23 // //n+(n-1)+...+(n-i+1) 24 // ans+=(2*n-i+1)*i/2; 25 // } 26 //错误,无法处理如2 2 4 2的数据 27 } 28 printf("%lf",(double)(ans*2-n)/(double)n/(double)n); 29 return 0; 30 }