• [Contest on 2022.7.1] 烦烦烦烦烦烦烦


    \(\cal T_2\) 刮痧

    Description

    这天 Colin 教 Eva 打隔膜,考虑到 Eva 胆子很小,Colin 决定教她刮痧流打法。

    Eva 使用的英雄是 Scraping Queen,每次攻击可以使选定的目标生命值 \(−1\),可以攻击 \(m\) 次。教程关一共有 \(n\) 个怪物,第 \(i\) 个生命值为 \(a_i\),都没有攻击力,排成一排等着挨打。

    虽然怪物不会进攻,但是长相实在是太恐怖了,Eva 还是很害怕,只敢闭上眼乱砍。所以每次行动她会随机选一个当前生命值 \(> 0\) 的怪物攻击。

    现在 Colin 想知道,经过 \(m\) 次攻击后,Eva 能击败的怪物期望数。称一个怪物被击败,当且仅当某一时刻其生命值等于零。

    \(n\leqslant 15,1\leqslant m,a_i\leqslant 100,\sum a_i\geqslant m\).

    Solution

    \(\bold{Warning}\):题解复读机。

    首先可以想出一个关于怪物血量的 \(\mathtt{dp}\),但这需要优化:可以想到,如果我们已经知道最后哪些怪物会死,就不需要记录下怪物的血量,只需要在打怪的时候乘上打若干次某怪的系数即可。

    \(g(i,S)\) 为对 \(j\in S\) 的怪物一共砍 \(i\) 刀且都不砍死的方案数,每次往集合中加怪需要 \(\mathcal O(m^2)\)\(\mathtt{dp}\),所以是 \(\mathcal O(2^nm^2)\) 的。

    \(f(i,S)\) 为砍 \(i\) 刀使得 \(j\in S\) 的怪物都死亡的概率(不计算没有砍死的怪物),\(\text{sum}(S)\) 为集合 \(S\) 中怪物的血量和。那么第 \(i+1\) 刀有以下情况:

    • 砍死一只怪,设其为 \(j\)。那么 \(i-\text{sum}(S)\) 中有 \(a_j-1\) 次砍在 \(j\) 怪上,贡献是 \(\displaystyle \dbinom{i-\text{sum}(S)}{a_j-1}\big /|U\setminus S|\)
    • 没砍死。贡献是 \(1\big /|U\setminus S|\).

    这个复杂度是 \(\mathcal O(2^nnm)\) 的。总复杂度 \(\mathcal O(2^nm(n+m))\).

    Code

    # include <cstdio>
    # include <cctype>
    # define print(x,y) write(x), putchar(y)
    
    template <class T>
    inline T read(const T sample) {
        T x=0; char s; bool f=0;
        while(!isdigit(s=getchar())) f|=(s=='-');
        for(; isdigit(s); s=getchar()) x=(x<<1)+(x<<3)+(s^48);
        return f? -x: x;
    }
    template <class T>
    inline void write(T x) {
        static int writ[50], w_tp=0;
        if(x<0) putchar('-'), x=-x;
        do writ[++w_tp]=x-x/10*10, x/=10; while(x);
        while(putchar(writ[w_tp--]^48), w_tp);
    }
    
    # include <iostream>
    using namespace std;
    
    const int maxn = 1<<15;
    
    int n, m, a[20], sum[maxn], lg[maxn];
    long double f[105][maxn], C[105][105], g[105][maxn];
    
    int lowbit(int x) { return x&-x; }
    
    int main() {
        freopen("scraping.in","r",stdin);
        freopen("scraping.out","w",stdout);
        n=read(9), m=read(9); int lim=1<<n;
        for(int i=1;i<=n;++i) a[i]=read(9); lg[0]=-1;
        for(int i=1;i<lim;++i) {
            lg[i] = lg[i>>1]+1;
            sum[i] = sum[i^lowbit(i)]+a[lg[lowbit(i)]+1];
        } C[0][0]=1;
        for(int i=1;i<=m;++i) {
            C[i][0]=1;
            for(int j=1;j<=i;++j)
                C[i][j] = C[i-1][j]+C[i-1][j-1];
        } g[0][0]=1;
        for(int s=1;s<lim;++s) {
            int t = s^lowbit(s), k=lg[lowbit(s)]+1;
            for(int i=m;i>=0;--i)
                for(int j=min(a[k]-1,i);j>=0;--j)
                    g[i][s] += g[i-j][t]*C[i][j];
        } long double ans=0; f[0][0]=1;
        for(int s=0;s<lim-1;++s) {
            int cnt = n-__builtin_popcount(s);
            for(int i=sum[s];i<m;++i) {
                for(int j=1;j<=n;++j) if(!(s>>j-1&1)) 
                    f[i+1][s|(1<<j-1)] += f[i][s]*C[i-sum[s]][a[j]-1]/cnt;
                f[i+1][s] += f[i][s]/cnt;
            } 
        } 
        for(int s=0;s<lim;++s) if(m>=sum[s]) {
            int t = (lim-1)^s, cnt=__builtin_popcount(s);
            ans += f[m][s]*g[m-sum[s]][t]*cnt;
        } printf("%.5Lf\n",ans);
        return 0;   
    }
    

    \(\cal T_3\) 感染

    Description

    \(\mathcal{P}\text{ortal.}\)

    闲话:听说这题直接输出 \(n\)\(\text{40 pts}\),感觉自己还是胆子不够大啊(?

    Solution

    \(\color{black}{\bold{Warning}}\):没有代码实现,没有代码实现,没有代码实现。

    首先固定母体的方向,基于此每个点的方向实际是固定的。首先可以确定的是每个点都一定会向母体的方向走 —— 这样过于宽泛。事实上,假设母体初始坐标为 \((a,b)\),记点 \((p,q)\)\(x=a,y=b\) 这两条直线的距离分别为 \(A,B\),当 \(A\leqslant B\) 时,一定选向母体的竖直方向;反之选向母体的水平方向。

    现在考虑什么样的点 \(x\) 可能会被点 \(y\) 直接 传染。要么 \(x,y\) 相互在彼此的方向中,要么 \(x,y\) 形成的直线斜率为 \(1/-1\)(注意还需要判断一下方向)。于是可以考虑用 \(\rm dijkstra\) 来完成拓展,复杂度应当是 \(\mathcal O(n^2\log n)\) 的?

    考虑优化建图,可以给每个点建各个方向的虚点,把在一条平行于坐标轴/斜率为 \(1/-1\) 的直线上的点相邻进行连边,权值为距离。那么每个点只需要对各个方向连一个最近的虚点即可,复杂度 \(\mathcal O(n\log n)\).

    Code

    愿神保佑您。
    
  • 相关阅读:
    游千佛塔有感
    时刻坚持高标准:成大事者的十条“箴言”
    谁愿意嫁给我这样的人
    成功的秘诀之一,就是敢于提出大设想、大思考
    寒冬里的暖阳
    世界最伟大的管理原则
    把你藏在心里
    登天门有感
    办公室保持最佳状态的诀窍
    “领悟”的价值是什么?思维能力训练问答
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/16435242.html
Copyright © 2020-2023  润新知