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 }

 

posted @ 2017-09-07 17:12  hehe_54321  阅读(442)  评论(0编辑  收藏  举报
AmazingCounters.com