• 【10.5校内测试】【DP】【概率】


    转移都很明显的一道DP题。按照不优化的思路,定义状态$dp[i][j][0/1]$表示吃到第$i$天,当前胃容量为$j$,前一天吃(1)或不吃(0)时能够得到的最大价值。

    因为有一个两天不吃可以复原容量的定义,所以需要前一天的状态。

    而注意,容量表示的是当前第$i$天吃之前的容量。

    然后考虑压缩空间,将天数滚动。要注意的是滚动过后$now$指向的是$i$后一天的状态,因此刷表更新。

    #include<bits/stdc++.h>
    using namespace std;
    
    int n, m;
    int a[1005], dp[2][20005][3], ap[20005];
    
    int main() {
        freopen("buffet.in", "r", stdin);
        freopen("buffet.out", "w", stdout);
        scanf("%d%d", &n, &m);
        int ans = 0;
        for(int i = 1; i <= n; i ++)    scanf("%d", &a[i]);
        ap[1] = m;
        for(int i = 2; i <= n; i ++) ap[i] = ap[i-1] * 2 / 3;
        int now = 0;
        memset(dp[now], -1, sizeof(dp[now]));
        dp[0][1][0] = 0; 
        for(int i = 1; i <= n; i ++) {
            now ^= 1;
            memset(dp[now], -1, sizeof(dp[now]));
            for(int j = 1; j <= n; j ++) {
                if(~dp[now^1][j][0]) {
                    dp[now][1][0] = max(dp[now][1][0], dp[now^1][j][0]);
                    dp[now][j+1][1] = max(dp[now][j+1][1], dp[now^1][j][0] + min(a[i], ap[j]));
                }
                if(~dp[now^1][j][1]) {
                    dp[now][j+1][1] = max(dp[now][j+1][1], dp[now^1][j][1] + min(a[i], ap[j]));
                    dp[now][j-1][0] = max(dp[now][j-1][0], dp[now^1][j][1]);
                }
            }
        }
        for(int i = 1; i <= n; i ++)
            ans = max(ans, max(dp[now][i][1], dp[now][i][0]));
        printf("%d", ans);
        return 0;
    }

    概率神题,三校只有$yuli$dalao$A$掉了%%%%

    非常神奇的记忆化搜索,就算我能把式子推出来也会弄晕的QAQ

    定义$dp[i][j]$表示当前剩余$i$个人,当前编号为$j$的人的存活概率。枪在当前1号手中。

    注意这个当前,表示的是此时剩下来的人重新从0编号。

    可以推出转移式子:$dp[i][j]=q*dp[i-1][j-1]+(1-q)*dp[i][(j-kmodi+i)modi]$,$q$表示当前这枪打出去能打出来的概率。$q=(i-1)/C$,因为当前子弹比人数要少1。前一个式子是打出了这个枪,于是0死了,j在剩下的人中号数要-1,(1把枪移交2相当与2变为了现在的1),后面的式子是打了空枪,枪移交给后面第k个人,同样也是把整个队列往前移k位。

    观察式子可以发现,$dp[i-1][j-1]$我们可以在记忆化搜索中递归求得,而后面$dp[i][(j-kmodi+i)modi]$是与$dp[i][j]$同层的,考虑怎么求得。

    可以发现,如果一直打空枪,从$j$开始,一定可以通过环走回$j$。所以在递归边界式子变为$dp[i][j]=o+(1-q)^ndp[i][j]$,其中每个$(1-q)$虽然不同,但在搜索过程中可以顺便算出来。$o$表示的是在以后的层数中可以求得的,因为我们可以把$dp[i][(j-kmodi+i)modi]$带入最开始的转移式,再把它们按层数分离。然后就按分离出来的式子将每一步更新即可。

    过程中记忆化即可。然后概率要用逆元,可以预处理出来。

    #include<bits/stdc++.h>
    #define LL long long
    #define mod 1000000009
    using namespace std;
    
    int T, N, C, K;
    
    int vf[1005];
    int dp[1005][1005], vis[1005][1005];
    LL mpow(int a, LL b) {
        LL ans = 1;
        for(; b; b >>= 1, a = 1ll * a * a % mod)
            if(b & 1)    ans = 1ll * ans * a % mod;
        return ans;
    }
    
    int dfs(int res, int pos, int oo, int gl) {
        if(pos == -1)    return 0;
        if(res == 1)    return 1;
        if(vis[res][pos] && dp[res][pos] == -1) {//同层中走回来了 可以直接算 
            dp[res][pos] = 1ll * oo * mpow((1 - gl + mod) % mod, mod - 2) % mod;
            return dp[res][pos];
        }
        if(vis[res][pos])    return dp[res][pos];//记忆化 
        vis[res][pos] = 1;
        dfs(res, (pos - K % res + res) % res, (oo + 1ll * gl * (res - 1) % mod * vf[C] % mod * dfs(res - 1, pos - 1, 0, 1) % mod) % mod, 1ll * gl * (C - res + 1) % mod * vf[C] % mod);//子弹共有res-1个 
        if(~dp[res][pos])    return dp[res][pos];
        dp[res][pos] = (1ll * (res - 1) * vf[C] % mod * dfs(res - 1, pos - 1, 0, 1) % mod + 1ll * (C - res + 1) * vf[C] % mod * dp[res][(pos - K % res + res) % res] % mod) % mod;
        return dp[res][pos];
    }
    
    int main() {
        freopen("gun.in", "r", stdin);
        freopen("gun.out", "w", stdout);
        scanf("%d", &T);
        for(int i = 1; i <= 1000; i ++)    vf[i] = mpow(i, mod - 2);
        while(T --) {
            memset(vis, 0, sizeof(vis));
            memset(dp, -1, sizeof(dp));
            scanf("%d%d%d", &N, &C, &K);
            for(int i = 0; i < N; i ++)
                printf("%d ", dfs(N, i, 0, 1));
            printf("
    ");
        }
    }
  • 相关阅读:
    MT【126】点对个数两题之二【图论】
    MT【125】四点共圆
    MT【124】利用柯西求最值
    MT【123】利用第一次的技巧
    MT【122】一个重要的不平凡的无穷级数
    MT【121】耐克数列的估计
    MT【120】保三角函数
    MT【119】关于恒成立的一道压轴题
    计算机视觉目标检测的框架与过程
    使用模板类导致error LNK2019: 无法解析的外部符号
  • 原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9745140.html
Copyright © 2020-2023  润新知