一道题19

$n \leq 100000$的数列给$m \leq 100000$个操作:操作一,单点修改;操作二,现给$t$种颜色,每种颜色数量给出,加起来为$n-1$,对除了询问给的$k$以外的每个数随机涂色;对一个$k$开始,公差$d$,往左右延伸的下标等差数列$a_i=k+id,L<=i<=R,L<=0<=R$,取极小的$L$和极小的$R$使得这些数字的颜色与$k$相同,加进答案,选择一种给$k$染色的方案($t$种之一)使期望答案最小,并输出这个答案。

什么鬼畜操作。。

首先$c$肯定选最小的一个,把期望分解成每一个数字选中的概率,对$K$右边的数,就是他左边一坨数(下标每次$-d$,直到$K+d$)和他自己都选中的的概率,就是他对答案有贡献的概率。$c$较小时这个概率乘没几下就变0了,但$c$可能达到$n-1$级别。

仔细分析,$c$只有在$t=1$时才会使概率很大,此时概率为1,就相当于一个等差数列下标的数字求和,可以分块。而$t>1$后,$c$最大为$\frac{n-1}{2}$,此时一个,两个,三个颜色与$K$相同的概率分别是$\frac{c}{n-1},\frac{c}{n-1}*\frac{c-1}{n-2},\frac{c}{n-1}*\frac{c-1}{n-2}*\frac{c-2}{n-3}...$,第一个数字只有$\frac{1}{2}$,后面乘不多次就会变得很小,于是算到一定程度,概率很小可以忽略时退出循环。

 1 //#include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 //#include<time.h>
 5 //#include<complex>
 6 //#include<set>
 7 //#include<queue>
 8 //#include<vector>
 9 #include<algorithm>
10 #include<stdlib.h>
11 using namespace std;
12 
13 #define LL long long
14 int qread()
15 {
16     char c; int s=0,f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1);
17     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f;
18 }
19 
20 //Pay attention to '-' , LL and double of qread!!!!
21 
22 int n,m,bl;
23 #define maxn 100011
24 int a[maxn],b[411][411];
25 
26 int main()
27 {
28     n=qread(); bl=min(n,400); m=qread();
29     for (int i=1;i<=n;i++) a[i]=qread();
30     for (int i=1;i<=bl;i++)
31         for (int j=1;j<=i;j++)
32             for (int k=j;k<=n;k+=i)
33                 b[i][j]+=a[k];
34     
35     int op,t,K,d,c;
36     while (m--)
37     {
38         op=qread();
39         if (op==1)
40         {
41             K=qread(); d=qread();
42             for (int i=1;i<=bl;i++)
43             {
44                 int j=(K-1)%i+1;
45                 b[i][j]+=d-a[K];
46             }
47             a[K]=d;
48         }
49         else
50         {
51             t=qread(); K=qread(); d=qread(); c=qread(); t--;
52             if (t==0) printf("%d.000000\n",b[d][(K-1)%d+1]);
53             else
54             {
55                 while (t--) {c=min(c,qread());}
56                 double ans=a[K],tmp=1;
57                 for (int i=K+d,w=0;i<=n && w<=bl;i+=d,w++)
58                 {
59                     if (w==c) tmp=0;
60                     if (tmp<1e-12) break;
61                     tmp*=1.0*(c-w)/(n-1-w);
62                     ans+=tmp*a[i];
63                 }
64                 tmp=1;
65                 for (int i=K-d,w=0;i>=1 && w<=bl;i-=d,w++)
66                 {
67                     if (w==c) tmp=0;
68                     if (tmp<1e-12) break;
69                     tmp*=1.0*(c-w)/(n-1-w);
70                     ans+=tmp*a[i];
71                 }
72                 printf("%.6lf\n",ans);
73             }
74         }
75     }
76     return 0;
77 }
View Code

 

转载于:https://www.cnblogs.com/Blue233333/p/9179620.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,以下是一道难度较高的 C++ 类与对象目: 编写一个名为 `Shape` 的基类,包含一个纯虚函数 `getArea()` 用于计算图形面积。然后编写两个派生类 `Rectangle` 和 `Circle`,分别用于表示矩形和圆形。这两个类都应该覆盖 `Shape` 基类中的 `getArea()` 函数。 在 `main()` 函数中,创建一个 `Shape` 类型的指针数组,该数组包含三个指针,分别指向一个 `Shape` 对象、一个 `Rectangle` 对象和一个 `Circle` 对象。然后使用循环遍历该数组,对于每个对象,调用它的 `getArea()` 函数并输出结果。 提示:可以使用多态来实现这个问。 ### 回答2: 假设有一个类叫做"人",它具有以下属性和方法: 属性:姓名(name),年龄(age),学号(student_id) 方法: - 学习(study):打印出"姓名[姓名]正在学习" - 年龄加一(increment_age):将年龄增加1 - 获取学号(get_student_id):返回学号 现在需要编写一个方法,名为"最年长学生",该方法接收一个人对象的列表作为参数,并返回列表中年龄最大的学生对象。 解决方法如下: ``` class 人: def __init__(self, name, age, student_id): self.name = name self.age = age self.student_id = student_id def study(self): print("姓名%s正在学习" % self.name) def increment_age(self): self.age += 1 def get_student_id(self): return self.student_id def 最年长学生(人列表): 最年长的学生 = None 最大年龄 = 0 for 人对象 in 人列表: if 人对象.age > 最大年龄: 最大年龄 = 人对象.age 最年长的学生 = 人对象 return 最年长的学生 人列表 = [ 人("小明", 18, "001"), 人("小红", 20, "002"), 人("小刚", 19, "003") ] 最年长的学生 = 最年长学生(人列表) print("年龄最大的学生是:%s,年龄为:%d,学号为:%s" % (最年长的学生.name, 最年长的学生.age, 最年长的学生.student_id)) ``` 这段代码定义了一个人类,并实现了最年长学生方法来找到年龄最大的学生对象。在最年长学生方法中,我们通过遍历人列表,逐个比较人对象的年龄,找到最大的年龄并记录下对应的学生对象。最后返回最年长的学生对象,然后在主函数中打印出最年长学生的姓名、年龄和学号。 ### 回答3: 目:请设计一个类,实现一个简单的计算器功能。 要求: 1. 计算器能够进行加、减、乘、除运算。 2. 计算器能够存储历史运算记录,并能够返回最近一次的运算结果。 3. 计算器的初始化结果为0。 4. 计算器需要具有对运算数的输入和获取功能。 解答: ```python class Calculator: def __init__(self): self.result = 0 self.history = [] # 用于存储历史运算记录 def add(self, num): self.result += num self.history.append("+" + str(num)) def subtract(self, num): self.result -= num self.history.append("-" + str(num)) def multiply(self, num): self.result *= num self.history.append("*" + str(num)) def divide(self, num): if num != 0: self.result /= num self.history.append("/" + str(num)) else: print("除数不能为零!") def get_result(self): return self.result def get_history(self): return self.history[-1] if self.history else "无历史记录" ``` 这个类通过实例化计算器类,我们可以进行各种运算操作。例如: ```python c = Calculator() c.add(10) # 将result加上10 print(c.get_result()) # 输出:10 c.subtract(5) # 将result减去5 print(c.get_result()) # 输出:5 c.multiply(3) # 将result乘以3 print(c.get_result()) # 输出:15 c.divide(0) # 尝试将result除以0,输出除数不能为零的提示信息 print(c.get_result()) # 输出:15 print(c.get_history()) # 输出最近一次的运算记录:“/0” ``` 这个计算器类包含了四个基本的运算方法:add、subtract、multiply和divide,对应四种基本运算。通过调用这些方法,我们可以实现我们想要的计算操作,并且能够获取结果和查看历史记录。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值