$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}$,后面乘不多次就会变得很小,于是算到一定程度,概率很小可以忽略时退出循环。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }