• 【思维题 阈值 期望】10.3奥义商店


    真是非常可惜……一是阈值不会用;二是期望不熟悉。考场的idea已经直逼标算了。

    题目描述

    乐滋滋经常参加各种拍卖会,前不久,他收到了来自滋滋国最大的商店——奥义商店的拍卖会邀请函。

    为了让拍卖会看起来更加奥妙重重,奥义商店设置了一个极为复杂的拍卖规则:一共 $n$ 个物品排成一排,第 $i$ 个物品价格是 $v_i$​ 。对于一次拍卖,商店会指定 $t$ 种颜色,并对每种颜色指定一个数目 $c_j$​ 满足 $sum_{j=1}^{t}c_j=n-1$ ,另外还会指定一个下标 $k$ 和一个公差 $d$ 。

    买家需要给第 $k$ 个物品染上一种颜色(在 $t$ 种颜色中选择一种)。接着,把剩下的 $n-1$ 个物品随机染成 $t$ 种颜色之一,并保证这 $n-1$ 个物品中第 $j$ 种颜色的恰好有 $c_j$​个。

    买家需要购买的物品按这样的方式计算:找到 $k$ 所在的最长的以 $d$ 为公差的等差数列 $a_x=kx+d(xin [L,R],Lle 0 le R)$ 满足其中所有物品都与第 $k$ 个物品同色。买家需要买下这个等差数列中的所有物品,显然花费就是 $sum_{x=L}^{R}v_{k+xd}$​ 。

    乐滋滋最近出现了点“经济危机”,希望你能帮他给第 $k$ 个物品选择合适的颜色,以此来最小化他花费的期望,你只需要输出这个期望即可。

    当然商品的价格是可能出现变动的,你需要维护这些变化。

    数据范围

    $1 leq n,m leq 10^5$


    题目分析

    我考试时候在想什么,为什么现在看这题觉得好简单啊……

    不知道过几天还会不会做

    这里是一些零碎的做完题的想法:既然要求期望代价最小,那么每一次第$k$个物品应该染成$min$ $c_j$。然后把期望拆开,就是每一个位置被统计到的概率乘以它的权值。这个概率不是很难算,就是从前一个位置转移过来的概率。

    以上就是一个正确但是非常慢的想法。

    算法的复杂度是$O(mn/d)$的,当$d$比较小时,复杂度就接近$O(nm)$。

    可能会说:那么把d阈值一下就好了嘛,d小的时候用$s[d][j]$表示模$d$为j的vi总和。然而只阈值d只能在$t=1$时有效。若$t!=1$还是需要枚举计算期望。然后非常玄学的精度阈值就来了:

    但是要注意!最好不要形如 if (sta*v[k-i*d] < 1e-13) break; 的精度阈值。因为尽管看上去增量已经很小了,但实际上是不能这样“意会”的。

    所以以上就是这题的两个玄学阈值。

     1 #include<cstdio>
     2 #include<cctype>
     3 const int maxn = 100035;
     4 
     5 double ans,sta,s[103][103];
     6 int n,m,t,k,d,mn;
     7 int v[maxn],c[maxn];
     8 
     9 int read()
    10 {
    11     char ch = getchar();
    12     int num = 0;
    13     bool fl = 0;
    14     for (; !isdigit(ch); ch=getchar())
    15         if (ch=='-') fl = 1;
    16     for (; isdigit(ch); ch=getchar())
    17         num = (num<<1)+(num<<3)+ch-48;
    18     if (fl) num = -num;
    19     return num;
    20 }
    21 int min(int a, int b){return a<b?a:b;}
    22 int main()
    23 {
    24     freopen("lzz.in","r",stdin);
    25     freopen("lzz.out","w",stdout);
    26     n = read(), m = read();
    27     for (int i=1; i<=n; i++)
    28     {
    29         v[i] = read();
    30         for (int j=1; j<=100; j++)
    31             s[j][i%j] += v[i];
    32     }
    33     while (m--)
    34     {
    35         int opt = read();
    36         if (opt==1){
    37             int x = read(), y = read();
    38             for (int j=1; j<=100; j++)
    39                 s[j][x%j] += y-v[x];
    40             v[x] = y;
    41         }else{
    42             t = read(), k = read(), d = read(), mn = n-1, ans = v[k], sta = 1.0;
    43             for (int i=1; i<=t; i++) c[i] = read(), mn = min(mn, c[i]);
    44             if (t==1){
    45                 if (d<=100) ans = s[d][k%d];
    46                 else{
    47                     for (int i=k+d; i<=n; i+=d) ans += v[i];
    48                     for (int i=k-d; i>=1; i-=d) ans += v[i];
    49                 }
    50             }else{
    51                 for (int i=1; i<=100&&k+i*d<=n; i++)
    52                 {
    53                     sta *= 1.0*(mn-i+1)/(n-i);
    54                     ans += sta*v[k+i*d];
    55                 }
    56                 sta = 1.0;
    57                 for (int i=1; i<=100&&k-i*d>=1; i++)
    58                 {
    59                     sta *= 1.0*(mn-i+1)/(n-i);
    60                     ans += sta*v[k-i*d];
    61                 }
    62             }
    63             printf("%.6lf
    ",ans);
    64         }
    65     }
    66     return 0;
    67 }

    鬼知道我考试时候在写什么……

    #include<bits/stdc++.h>
    const int maxn = 100035;
    
    double ans,sta;
    int n,m,t,k,d,mn;
    int v[maxn],c[maxn];
    
    int read()
    {
        char ch = getchar();
        int num = 0;
        bool fl = 0;
        for (; !isdigit(ch); ch=getchar())
            if (ch=='-') fl = 1;
        for (; isdigit(ch); ch=getchar())
            num = (num<<1)+(num<<3)+ch-48;
        if (fl) num = -num;
        return num;
    }
    int main()
    {
        freopen("lzz.in","r",stdin);
        freopen("lzz.out","w",stdout);
        n = read(), m = read();
        for (int i=1; i<=n; i++) v[i] = read();
        while (m--)
        {
            int opt = read();
            if (opt==1){
                int x = read(), y = read();
                v[x] = y;
            }
            else{
                t = read(), k = read(), d = read(), mn = n-1, ans = v[d], sta = 1.0;
                for (int i=1; i<=t; i++) c[i] = read(), mn = std::min(mn, c[i]);
                for (int i=2; i<=c[i]+1; i++)
                {
                    sta *= (c[i]-i+2.0)/(n-i+1.0);
                    ans += sta*v[i];
                }
                printf("%.6lf
    ",ans);
            }
        }
        return 0;
    }
    鬼畜代码

    END

  • 相关阅读:
    【转发】JS中如何判断null/ undefined/IsNull
    CSS3实现两行或三行文字,然后多出的部分省略号代替
    关于CodeFirst的使用教程
    把一个字符串里符合表情文字标签的地方全部替换为相应的图片的方法
    js 给json添加新的字段,或者添加一组数据,在JS数组指定位置删除、插入、替换元素
    用css3选择器给你要的第几个元素添加不同样式方法【转发】
    WebApi2 知识点总结
    把字符串每隔四个字符使用“-”中横线分隔的方法
    C语言strchr()函数:查找某字符在字符串中首次出现的位置
    linux 下安装开发组件包
  • 原文地址:https://www.cnblogs.com/antiquality/p/9740008.html
Copyright © 2020-2023  润新知