思路:首先考虑t=1的情况,t等于1,那么所有位置的颜色相同,我们不用考虑概率的问题,那么,k+d*x在模d下都相等,我们考虑预处理一个数组s[i][j],代表d为i,起始位置为j的等差数列的和,这个可以证明,当模小于等于sqrt(n)的时候可以完美解决,时间复杂度为N^1.5,对于d大于sqrt(n)的情况,只需要暴力枚举就可以了。
再考虑t>=2的情况,我们选的颜色一定是颜色数最少的那个,颜色数最少的颜色的期望绝对是最小的,然后,我们分k的左边和k的右边进行计算,我们这里称呼k+d*x的位置,叫做关键位置,假设p[i]为i到k这一段上所有的关键位置全部都是同一个颜色的概率,那么转移,就是p[i+k]=p[i]*(x)/(n-1-x),x为最少的颜色个数。我们可以发现,x<(n-1)/2,p[i]是随指数级衰减的,那么我们只需要枚举一小段,当p[i]<eps时,那么它对答案就几乎没有影响了。
1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 int block,n,m; 7 int s[2005][2005],a[200005]; 8 const double eps=1e-16; 9 int read(){ 10 int t=0,f=1;char ch=getchar(); 11 while (ch<‘0‘||ch>‘9‘){if (ch==‘-‘) f=-1;ch=getchar();} 12 while (‘0‘<=ch&&ch<=‘9‘){t=t*10+ch-‘0‘;ch=getchar();} 13 return t*f; 14 } 15 void init(){ 16 n=read();m=read(); 17 for (int i=1;i<=n;i++) a[i]=read(); 18 block=ceil(sqrt(n))+0.1; 19 for (int i=1;i<=block;i++) 20 for (int j=1;j<=i;j++) 21 for (int k=j;k<=n;k+=i) 22 s[i][j]+=a[k]; 23 } 24 void modify(int x,int y){ 25 int T=y-a[x]; 26 for (int i=1;i<=block;i++) 27 s[i][(x-1)%i+1]+=T; 28 a[x]=y; 29 } 30 double deal(int k,int d){ 31 if (d<=block) return s[d][(k-1)%d+1]; 32 double res=0; 33 for (int i=(k-1)%d+1;i<=n;i+=d) 34 res+=(double)a[i]; 35 return res; 36 } 37 void solve(){ 38 while (m--){ 39 int opt=read(); 40 if (opt==1){ 41 int x=read(),y=read(); 42 modify(x,y);continue; 43 } 44 int num=0x7fffffff,t,k,d; 45 t=read();k=read();d=read();for (int i=1;i<=t;i++){int l=read();num=std::min(num,l);} 46 if (t==1) {printf("%.4f\n",deal(k,d));continue;} 47 double ans=(double)a[k],p=1; 48 int N=num; 49 for (int i=k+d,Num=n-1;i<=n&&num>0;i+=d,Num--,num--){ 50 p=p*num/Num;ans+=p*a[i]; 51 if (p<eps&&n>=1000) break; 52 } 53 num=N;p=1; 54 for (int i=k-d,Num=n-1;i>=1&&num>0;i-=d,Num--,num--){ 55 p=p*num/Num;ans+=p*a[i]; 56 if (p<eps&&n>=1000) break; 57 } 58 printf("%.4f\n",ans); 59 } 60 } 61 int main(){ 62 init(); 63 solve(); 64 }
时间: 2024-10-11 00:13:12