奥义商店
有一个商店,n个物品,每个物品有一个价格和一种颜色。
有m个操作,操作有两种,一种是修改一个位置的价格,另一种是购买,每次购买指定一个公差d和一个位置k,找到包含这个位置k公差为d的同色最长等差数列,买下所有物品。让你给这个位置染成t种颜色中的一种(你来指定),其他位置会随机染成t种颜色之一,并保证这n-1个物品中第j种颜色的恰好有c[j]个。求最小期望花费保留四位小数。
注意询问相互独立,询问不会买走物品。
1<=n,m<=10^5,∑t<=2*10^5。
样例输入:
3 3
1 1 1
2 2 1 1 1 1
1 2 2
2 2 3 1 1 1
样例输出
1.5000
2.0000
先考虑t=1时
这样我们就要找到所有mod d与k同余的数之和
考虑分块考虑
lim=√n
当d<=lim时,它的元素个数会>lim,预处理出和每一个d<=lim的和
当d>lim时,直接枚举求和
接下来考虑t>1,那么看完分析就知道为什么t=1要单独考虑
要使花的钱最少,你选择的肯定是出现概率最少的颜色,设它有$c$个
假设直到$k+x*d$有贡献,那么要求$k+d,k+2*d,....k+x*d$都是这个颜色
设$p[i]$表示到$k+i*d$有贡献
这样染色的方案数,那么剩下$n-1-p$个只能有$c-p$个为这个颜色,方案数就是$C_{n-1-p}^{c-p}$
而概率就是$\frac{C_{n-1-p}^{c-p}}{C_{n-1}^{c}}$。
可得$p[i]=p[i-1]*\frac{c-i+1}{n-i}$
但是这样也会超时
我们发现$t>1$时$c<=(n-1)/2$
于是$\frac{\frac{n-1}{2}-i+1}{n-i}<=0.5$
所以p会指数级下降,所以到了大概100位就基本为0了
所以复杂度$O(m√n+m*100)$
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #include<cmath> 7 using namespace std; 8 double ans; 9 int s[401][100001],v[100001]; 10 double p[101]; 11 int n,q,lim,opt,minc,c[200001]; 12 int main() 13 {int i,j,t,x,k,d; 14 double y; 15 freopen("lzz.in","r",stdin); 16 freopen("lzz.out","w",stdout); 17 cin>>n>>q; 18 lim=sqrt(n); 19 for (i=1;i<=n;i++) 20 { 21 scanf("%d",&v[i]); 22 } 23 for (i=1;i<=lim;i++) 24 { 25 for (j=1;j<=n;j++) 26 { 27 s[i][j%i]+=v[j]; 28 } 29 } 30 while (q--) 31 { 32 scanf("%d",&opt); 33 if (opt==1) 34 { 35 scanf("%d%lf",&x,&y); 36 for (i=1;i<=lim;i++) 37 { 38 s[i][x%i]+=y-v[x]; 39 } 40 v[x]=y; 41 } 42 else 43 { 44 scanf("%d%d%d",&t,&k,&d); 45 minc=2e9; 46 for (i=1;i<=t;i++) 47 { 48 scanf("%d",&c[i]); 49 minc=min(minc,c[i]); 50 } 51 if (t==1) 52 { 53 ans=0; 54 if (d<=lim) 55 { 56 ans=s[d][k%d]; 57 } 58 else 59 { 60 for (i=k;i<=n;i+=d) ans+=v[i]; 61 for (i=k-d;i>=1;i-=d) ans+=v[i]; 62 } 63 printf("%.4lf\n",ans); 64 } 65 else 66 { 67 p[0]=1; 68 ans=0; 69 for (i=1;i<=100;i++) 70 if (i>minc) p[i]=0; 71 else p[i]=p[i-1]*(double)(minc-i+1)/(double)(n-i); 72 for (i=k,t=0;i<=n&&t<=100;i+=d,t++) 73 ans+=v[i]*p[t]; 74 for (i=k-d,t=1;i>=1&&t<=100;i-=d,t++) 75 ans+=v[i]*p[t]; 76 printf("%.4lf\n",ans); 77 } 78 } 79 } 80 }