【线段树 泰勒展开】Codechef April Challenge 2018 Chef at the Food Fair
第一次写泰勒展开;本地和CC差距好大
题目大意
大厨住的城市里办了一场美食节。一条街上开设了$N$个摊位,编号为$1∼N$。这天开始时,第$i$个摊位的食物会导致食物中毒的概率是$P_i$。在这一天中,大厨发现某些摊位可能会根据顾客的反馈提供没那么有毒的食物。你需要处理$Q$个询问,询问有以下两类:
0 L R:求出:如果要吃遍$[L,R]$内所有摊位的食物,那么不会食物中毒的概率是多少;
1 L R T:$[L,R]$中的所有摊位的食物会导致食物中毒的概率变为了原来的$T$倍。$T$是一个小于$1$的非负实数。
对于前 $20\%$ 的数据,$n,m\le 2000$
另有 $20\%$ 的数据,$T\le 0.5$
对于 $100\%$ 的数据,满足 $n,m\le 10^5,0\le T<1,P_i\le 1,1\le L\le R\le n$,保证输入数据不超过 $6$ 位小数。
题目分析
注意到维护的操作有些不同寻常。
- 第一:维护的是$\prod (1-P_i)$
- 第二:每次操作是区间乘法
对于要求支持区间乘的问题,有一种转化套路是将它取$\ln$,那么问题就变成了维护区间和。
那么这题中还需要处理$\ln (1-P_i)$,将它泰勒展开得到$\ln(1-x)=x-{1\over 2}x^2-{1\over 3}x^3-...-{1\over n}x^n+R(x)$。我们一如既往地爆精度,只需要保留这个式子的前$MAXD=100$项和。维护时则是开$MAXD$颗线段树对每类次项分别处理区间乘法。
需要注意的是,这题需要一些常数技巧。我最先是开了$f[MAXD]$颗封装好的线段树,但由于数组的第一维是更频繁访问的一维,所以实际运行效率会比较低。如果采用形如$f[maxn<<2][MAXD]$的做法,就会快非常多。
非常迷的一点是,同一份代码在本地考试的数据下,极限数据要跑个4~5s;但是交到CC上就rank2了……
#include<bits/stdc++.h>
const int maxn = ;
const double eps = 1e-; int n,m,MAXD;
double p[maxn],w[maxn],K,S;
double f[maxn<<][],tag[maxn<<]; int read()
{
char ch = getchar();
int num = , fl = ;
for (; !isdigit(ch); ch=getchar())
if (ch=='-') fl = -;
for (; isdigit(ch); ch=getchar())
num = (num<<)+(num<<)+ch-;
return num*fl;
}
void pushup(int rt)
{
for (int i=; i<=MAXD; i++)
f[rt][i] = f[rt<<][i]+f[rt<<|][i];
}
void pushdown(int rt)
{
double v = tag[rt], s = tag[rt];
if (fabs(1.0-v) > eps){
tag[rt<<] *= v, tag[rt<<|] *= v;
for (int i=; i<=MAXD; i++)
f[rt<<][i] *= s, f[rt<<|][i] *= s, s *= v;
tag[rt] = 1.0;
}
}
void build(int rt, int l, int r)
{
tag[rt] = 1.0;
if (l==r){
for (int i=; i<=MAXD; i++)
w[l] *= p[l], f[rt][i] = w[l]/i;
return;
}
int mid = (l+r)>>;
build(rt<<, l, mid);
build(rt<<|, mid+, r);
pushup(rt);
}
double query(int rt, int L, int R, int l, int r)
{
if (L <= l&&r <= R){
double ret = ;
for (int i=; i<=MAXD; i++)
ret += f[rt][i];
return ret;
}
int mid = (l+r)>>;
double ret = ;
pushdown(rt);
if (L <= mid) ret += query(rt<<, L, R, l, mid);
if (R > mid) ret += query(rt<<|, L, R, mid+, r);
return ret;
}
void modify(int rt, int L, int R, int l, int r, double c)
{
if (L <= l&&r <= R){
double s = c;
tag[rt] *= s;
for (int i=; i<=MAXD; i++)
f[rt][i] *= s, s *= c;
return;
}
int mid = (l+r)>>;
pushdown(rt);
if (L <= mid) modify(rt<<, L, R, l, mid, c);
if (R > mid) modify(rt<<|, L, R, mid+, r, c);
pushup(rt);
}
int main()
{
n = read(), m = read();
for (int i=; i<=n; i++) scanf("%lf",&p[i]), w[i] = 1.0;
MAXD = ;
build(, , n);
for (int i=; i<=m; i++)
{
int opt = read(), l = read(), r = read();
if (opt){
scanf("%lf",&K);
modify(, l, r, , n, K);
}else{
K = query(, l, r, , n);
printf("%.8lf\n",exp(-K));
}
}
return ;
}
END
【线段树 泰勒展开】Codechef April Challenge 2018 Chef at the Food Fair的更多相关文章
- Codechef August Challenge 2018 : Chef at the River
传送门 (要是没有tjm(Sakits)的帮忙,我还真不知道啥时候能做出来 结论是第一次带走尽可能少的动物,使未带走的动物不冲突,带走的这个数量就是最优解. 首先这个数量肯定是下界,更少的话连第一次都 ...
- Codechef September Challenge 2018 游记
Codechef September Challenge 2018 游记 Magician versus Chef 题目大意: 有一排\(n(n\le10^5)\)个格子,一开始硬币在第\(x\)个格 ...
- Codechef April Challenge 2019 游记
Codechef April Challenge 2019 游记 Subtree Removal 题目大意: 一棵\(n(n\le10^5)\)个结点的有根树,每个结点有一个权值\(w_i(|w_i\ ...
- Codechef October Challenge 2018 游记
Codechef October Challenge 2018 游记 CHSERVE - Chef and Serves 题目大意: 乒乓球比赛中,双方每累计得两分就会交换一次发球权. 不过,大厨和小 ...
- CodeChef April Challenge 2019题解
传送门 \(Maximum\ Remaining\) 对于两个数\(a,b\),如果\(a=b\)没贡献,所以不妨假设\(a<b\),有\(a\%b=a\),而\(b\%a<a\).综上, ...
- Codechef August Challenge 2018 : Coordinate Compression
传送门 外边二分,里面拿线段树维护贪心就行了. #include<cstdio> #include<vector> #include<cstring> #inclu ...
- Codechef August Challenge 2019 Chef and Gordon Ramsay
[传送门] 题目即求所有的三元组,相对大小关系同 $p_1,p_2,p_3$. 题解说都很清楚,这里写一下过程整理一下思路. 如果我们枚举中间这个元素,那么就是统计子树内外有多少个大于这个数和小于这个 ...
- 2019.02.14 codechef Chef at the Food Fair(线段树+泰勒展开)
传送门 题意:现在有nnn个位置,每个位置上有一个值aia_iai. 要求支持如下两种操作: 区间乘vvv 求区间的(1−ai)(1-a_i)(1−ai)之积 思路: 考虑转换式子: Ans=∏i ...
- 【分块+树状数组】codechef November Challenge 2014 .Chef and Churu
https://www.codechef.com/problems/FNCS [题意] [思路] 把n个函数分成√n块,预处理出每块中各个点(n个)被块中函数(√n个)覆盖的次数 查询时求前缀和,对于 ...
随机推荐
- BitMap的原理以及运用
位图(Bitmap),即位(Bit)的集合,是一种数据结构,可用于记录大量的0-1状态,在很多地方都会用到,比如Linux内核(如inode,磁盘块).Bloom Filter算法等,其优势是可以在一 ...
- Ubuntu英文版中无法输入中文标点符号的问题
问题: 不管是中文还是英文输入法,输入的标点符号都是英文的 解决方法: ctrl + . 进行切换,一个是lation 符号,一个是全角符号
- 详解javascript中的this对象
详解javascript中的this对象 前言 Javascript是一门基于对象的动态语言,也就是说,所有东西都是对象,一个很典型的例子就是函数也被视为普通的对象.Javascript可以通过一定的 ...
- [TCP/IP]ICMP和IGMP的区别
ICMP(Internet 控制消息协议,Internet Control Message Protocol)协议用来给IP协议提供控制服务,允许路由器或目标主机给数据的发送方提供反馈信息.需要发送反 ...
- JavaScript读取文本,并渲染在html
html <pre id="myText" style="word-wrap: break-word; white-space: pre-wrap; white-s ...
- Java带token验证的注册登录
http://blog.csdn.net/huqingpeng321/article/details/52900550 http://blog.csdn.net/l18710006370/articl ...
- Spark Mllib里使用贝氏二元分类时如何将数值特征字段用StandardScaler进行标准化(图文详解)
不多说,直接上干货! NaiveBayes数值特征字段一定要大于0,所以加入下述命令将负数转换为0. 朴素贝叶斯分类算法在进行数据标准化时,参数withMean必须设置为false. 具体,见 Had ...
- Zepto核心模块源代码分析
一.Zepto核心模块架构 Zepto核心模块架构图 该图展示了Zepto核心模块架构代码的组织方式.主要分为私有变量.函数和暴露给用户的所有api. Zepto核心模块架构代码 该图展示了Zepto ...
- DatabaseMetaData类
DatabaseMetaData类是java.sql包中的类,利用它可以获取我们连接到的数据库的结构.存储等很多信息.如: 1.数据库与用户,数据库标识符以及函数与存储过程. 2.数据 ...
- shareTo 网页版分享
// share -------- var shareTo = function (dest, shareCode) { var appKey = "1667889534"; // ...