一道题19

$n \leq 100000$的数列给$m \leq 100000$个操作:操作一,单点修改;操作二,现给$t$种颜色,每种颜色数量给出,加起来为$n-1$,对除了询问给的$k$以外的每个数随机涂色;对一个$k$开始,公差$d$,往左右延伸的下标等差数列$a_i=k+id,L<=i<=R,L<=0<=R$,取极小的$L$和极小的$R$使得这些数字的颜色与$k$相同,加进答案,选择一种给$k$染色的方案($t$种之一)使期望答案最小,并输出这个答案。

什么鬼畜操作。。

首先$c$肯定选最小的一个,把期望分解成每一个数字选中的概率,对$K$右边的数,就是他左边一坨数(下标每次$-d$,直到$K+d$)和他自己都选中的的概率,就是他对答案有贡献的概率。$c$较小时这个概率乘没几下就变0了,但$c$可能达到$n-1$级别。

仔细分析,$c$只有在$t=1$时才会使概率很大,此时概率为1,就相当于一个等差数列下标的数字求和,可以分块。而$t>1$后,$c$最大为$\frac{n-1}{2}$,此时一个,两个,三个颜色与$K$相同的概率分别是$\frac{c}{n-1},\frac{c}{n-1}*\frac{c-1}{n-2},\frac{c}{n-1}*\frac{c-1}{n-2}*\frac{c-2}{n-3}...$,第一个数字只有$\frac{1}{2}$,后面乘不多次就会变得很小,于是算到一定程度,概率很小可以忽略时退出循环。

 1 //#include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 //#include<time.h>
 5 //#include<complex>
 6 //#include<set>
 7 //#include<queue>
 8 //#include<vector>
 9 #include<algorithm>
10 #include<stdlib.h>
11 using namespace std;
12 
13 #define LL long long
14 int qread()
15 {
16     char c; int s=0,f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1);
17     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f;
18 }
19 
20 //Pay attention to '-' , LL and double of qread!!!!
21 
22 int n,m,bl;
23 #define maxn 100011
24 int a[maxn],b[411][411];
25 
26 int main()
27 {
28     n=qread(); bl=min(n,400); m=qread();
29     for (int i=1;i<=n;i++) a[i]=qread();
30     for (int i=1;i<=bl;i++)
31         for (int j=1;j<=i;j++)
32             for (int k=j;k<=n;k+=i)
33                 b[i][j]+=a[k];
34     
35     int op,t,K,d,c;
36     while (m--)
37     {
38         op=qread();
39         if (op==1)
40         {
41             K=qread(); d=qread();
42             for (int i=1;i<=bl;i++)
43             {
44                 int j=(K-1)%i+1;
45                 b[i][j]+=d-a[K];
46             }
47             a[K]=d;
48         }
49         else
50         {
51             t=qread(); K=qread(); d=qread(); c=qread(); t--;
52             if (t==0) printf("%d.000000\n",b[d][(K-1)%d+1]);
53             else
54             {
55                 while (t--) {c=min(c,qread());}
56                 double ans=a[K],tmp=1;
57                 for (int i=K+d,w=0;i<=n && w<=bl;i+=d,w++)
58                 {
59                     if (w==c) tmp=0;
60                     if (tmp<1e-12) break;
61                     tmp*=1.0*(c-w)/(n-1-w);
62                     ans+=tmp*a[i];
63                 }
64                 tmp=1;
65                 for (int i=K-d,w=0;i>=1 && w<=bl;i-=d,w++)
66                 {
67                     if (w==c) tmp=0;
68                     if (tmp<1e-12) break;
69                     tmp*=1.0*(c-w)/(n-1-w);
70                     ans+=tmp*a[i];
71                 }
72                 printf("%.6lf\n",ans);
73             }
74         }
75     }
76     return 0;
77 }
View Code

猜你喜欢

转载自www.cnblogs.com/Blue233333/p/9179620.html