奥义商店

有一个商店,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 }

 

posted @ 2018-03-29 20:32  Z-Y-Y-S  阅读(365)  评论(0编辑  收藏  举报