BZOJ NOI十连测 第一测 T1
2016-06-15 19:46
357 查看
![](https://images2015.cnblogs.com/blog/911287/201606/911287-20160615194353338-527214483.png)
![](https://images2015.cnblogs.com/blog/911287/201606/911287-20160615194411682-78484930.png)
![](https://images2015.cnblogs.com/blog/911287/201606/911287-20160615194423182-1725649793.png)
![](https://images2015.cnblogs.com/blog/911287/201606/911287-20160615194434260-2126380396.png)
思路:首先考虑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时,那么它对答案就几乎没有影响了。
#include<algorithm> #include<cstdio> #include<cmath> #include<cstring> #include<iostream> int block,n,m; int s[2005][2005],a[200005]; const double eps=1e-16; int read(){ int t=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} while ('0'<=ch&&ch<='9'){t=t*10+ch-'0';ch=getchar();} return t*f; } void init(){ n=read();m=read(); for (int i=1;i<=n;i++) a[i]=read(); block=ceil(sqrt(n))+0.1; for (int i=1;i<=block;i++) for (int j=1;j<=i;j++) for (int k=j;k<=n;k+=i) s[i][j]+=a[k]; } void modify(int x,int y){ int T=y-a[x]; for (int i=1;i<=block;i++) s[i][(x-1)%i+1]+=T; a[x]=y; } double deal(int k,int d){ if (d<=block) return s[d][(k-1)%d+1]; double res=0; for (int i=(k-1)%d+1;i<=n;i+=d) res+=(double)a[i]; return res; } void solve(){ while (m--){ int opt=read(); if (opt==1){ int x=read(),y=read(); modify(x,y);continue; } int num=0x7fffffff,t,k,d; t=read();k=read();d=read();for (int i=1;i<=t;i++){int l=read();num=std::min(num,l);} if (t==1) {printf("%.4f\n",deal(k,d));continue;} double ans=(double)a[k],p=1; int N=num; for (int i=k+d,Num=n-1;i<=n&&num>0;i+=d,Num--,num--){ p=p*num/Num;ans+=p*a[i]; if (p<eps&&n>=1000) break; } num=N;p=1; for (int i=k-d,Num=n-1;i>=1&&num>0;i-=d,Num--,num--){ p=p*num/Num;ans+=p*a[i]; if (p<eps&&n>=1000) break; } printf("%.4f\n",ans); } } int main(){ init(); solve(); }
相关文章推荐
- 调用系统的分享功能
- 通过跳绳瘦下来是一种怎么样的体验?
- Mat
- 第十六周项目4:阅读下面的程序,指出其功能(3)
- 第十六周项目4:阅读下面的程序,指出其功能(2)
- android 自定义控件(二)
- 程序员的成长和代码行数的关系
- 手机端的轮播效果
- mysql数据库操作语法大全
- Universal-Image-Loader,android-Volley,Picasso、Fresco和Glide五大Android开源组件加载网络图片的优缺点比较
- 差分约束系统
- 第十六周项目4:阅读下面的程序,指出其功能(1)
- JSP中的MIME
- 第十六周项目3:查看下面程序的输出结果,并解释为什么
- 从古希腊神话说起,讲讲英语里的偏旁部首
- Cocos2d-Lua之运算符
- 第十六周项目2:阅读并运行程序,分别用记事本和二进制文件阅读器阅读(2)
- sws_scale YV12转RGB24图像倒转问题
- Linux系统调用
- 实现判断一组数据是否为可逆素数