BZOJ NOI十连测 第一测 T1

 思路:首先考虑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
",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
",ans);
59     }
60 }
61 int main(){
62     init();
63     solve();
64 }
原文地址:https://www.cnblogs.com/qzqzgfy/p/5588689.html