zoukankan      html  css  js  c++  java
  • 【线段树 泰勒展开】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,mle 2000$

    另有 $20\%$ 的数据,$Tle 0.5$

    对于 $100\%$ 的数据,满足 $n,mle 10^5,0le T<1,P_ile 1,1le Lle Rle n$,保证输入数据不超过 $6$ 位小数。


    题目分析

    注意到维护的操作有些不同寻常。

    • 第一:维护的是$prod (1-P_i)$
    • 第二:每次操作是区间乘法

    对于要求支持区间乘的问题,有一种转化套路是将它取$ln$,那么问题就变成了维护区间和。

    那么这题中还需要处理$ln (1-P_i)$,将它泰勒展开得到$ln(1-x)=x-{1over 2}x^2-{1over 3}x^3-...-{1over n}x^n+R(x)$。我们一如既往地爆精度,只需要保留这个式子的前$MAXD=100$项和。维护时则是开$MAXD$颗线段树对每类次项分别处理区间乘法。

    需要注意的是,这题需要一些常数技巧。我最先是开了$f[MAXD]$颗封装好的线段树,但由于数组的第一维是更频繁访问的一维,所以实际运行效率会比较低。如果采用形如$f[maxn<<2][MAXD]$的做法,就会快非常多。

    非常迷的一点是,同一份代码在本地考试的数据下,极限数据要跑个4~5s;但是交到CC上就rank2了……

     1 #include<bits/stdc++.h>
     2 const int maxn = 100035;
     3 const double eps = 1e-12;
     4 
     5 int n,m,MAXD;
     6 double p[maxn],w[maxn],K,S;
     7 double f[maxn<<2][103],tag[maxn<<2];
     8 
     9 int read()
    10 {
    11     char ch = getchar();
    12     int num = 0, fl = 1;
    13     for (; !isdigit(ch); ch=getchar())
    14         if (ch=='-') fl = -1;
    15     for (; isdigit(ch); ch=getchar())
    16         num = (num<<1)+(num<<3)+ch-48;
    17     return num*fl;
    18 }
    19 void pushup(int rt)
    20 {
    21     for (int i=1; i<=MAXD; i++)
    22         f[rt][i] = f[rt<<1][i]+f[rt<<1|1][i];
    23 }
    24 void pushdown(int rt)
    25 {
    26     double v = tag[rt], s = tag[rt];
    27     if (fabs(1.0-v) > eps){
    28         tag[rt<<1] *= v, tag[rt<<1|1] *= v;
    29         for (int i=1; i<=MAXD; i++)
    30             f[rt<<1][i] *= s, f[rt<<1|1][i] *= s, s *= v;
    31         tag[rt] = 1.0;
    32     }
    33 }
    34 void build(int rt, int l, int r)
    35 {
    36     tag[rt] = 1.0;
    37     if (l==r){
    38         for (int i=1; i<=MAXD; i++)
    39             w[l] *= p[l], f[rt][i] = w[l]/i;
    40         return;
    41     }
    42     int mid = (l+r)>>1;
    43     build(rt<<1, l, mid);
    44     build(rt<<1|1, mid+1, r);
    45     pushup(rt);
    46 }
    47 double query(int rt, int L, int R, int l, int r)
    48 {
    49     if (L <= l&&r <= R){
    50         double ret = 0;
    51         for (int i=1; i<=MAXD; i++)
    52             ret += f[rt][i];
    53         return ret;
    54     }
    55     int mid = (l+r)>>1;
    56     double ret = 0;
    57     pushdown(rt);
    58     if (L <= mid) ret += query(rt<<1, L, R, l, mid);
    59     if (R > mid) ret += query(rt<<1|1, L, R, mid+1, r);
    60     return ret;
    61 }
    62 void modify(int rt, int L, int R, int l, int r, double c)
    63 {
    64     if (L <= l&&r <= R){
    65         double s = c;
    66         tag[rt] *= s;
    67         for (int i=1; i<=MAXD; i++)
    68             f[rt][i] *= s, s *= c;
    69         return;
    70     }
    71     int mid = (l+r)>>1;
    72     pushdown(rt);
    73     if (L <= mid) modify(rt<<1, L, R, l, mid, c);
    74     if (R > mid) modify(rt<<1|1, L, R, mid+1, r, c);
    75     pushup(rt);
    76 }
    77 int main()
    78 {
    79     n = read(), m = read();
    80     for (int i=1; i<=n; i++) scanf("%lf",&p[i]), w[i] = 1.0;
    81     MAXD = 100;
    82     build(1, 1, n);
    83     for (int i=1; i<=m; i++)
    84     {
    85         int opt = read(), l = read(), r = read();
    86         if (opt){
    87             scanf("%lf",&K);
    88             modify(1, l, r, 1, n, K);
    89         }else{
    90             K = query(1, l, r, 1, n);
    91             printf("%.8lf
    ",exp(-K));
    92         }
    93     }
    94     return 0;
    95 }

    END

  • 相关阅读:
    delete与double free
    OpenCV(1)——基础数据结构CvMat
    防止表单自动提交_随笔2012年5月16日
    Flex 学习笔记学习资料
    当析构函数遇到多线程 ── C++ 中线程安全的对象回调
    .NET Core2.0+MVC 用session,cookie实现的sso单点登录
    TreeView中右击直接获取节点的方法
    webservice 远程调试配置
    数组,集合 转成DataTable 方法
    String类中几个简单的常用方法
  • 原文地址:https://www.cnblogs.com/antiquality/p/10385631.html
Copyright © 2011-2022 走看看