• E. Double Elimination (DP)


    题目:传送门

    题意:有 2^n 个人进行比赛,对他们编号 1~2^n,起初1和2打,3和4打,5和6打,7和8打...,然后1和2打完胜利的 和 3和4打完胜利的再打一场,1和2打完失败的和3和4打完失败的也再打一场,然后,失败组最终胜利的和胜利组最终胜利的再打一场。详情可看样例解释,结合着更容易理解。你有 k 个喜欢的队, 你想观看更多的你喜欢的队的比赛,你能决定比赛的胜利,问你最多能看多少场有你喜欢的队的比赛。

    2 <= n <= 17 ,  0 <= k <= 2^n

    题解: 这里有个视频的讲解 

    #include <bits/stdc++.h>
    #define LL long long
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF INT_MAX
    #define inf LLONG_MAX
    #define PI acos(-1)
    using namespace std;
    
    const int N = (1 << 17) + 5;
    ///设 dp[ i ][ j ][ f1 ][ f2 ] 为从 j 开始,连续的 2^(i - 1) 个人比赛,胜利组胜出的人 0/1(f1) 你喜欢的队,失败组胜出的人 0/1(f2) 你喜欢的队。
    int dp[20][N][2][2];
    int vis[N];
    int main() {
    
        int n, k, x; scanf("%d %d", &n, &k);
    
        rep(i, 1, k) {
            scanf("%d", &x);
            vis[x - 1] = 1;
        }
    
        mem(dp, -0x3f3f3f);
    
        rep(i, 1, n) {
            for(int j = 0; j < (1 << n); j += (1 << i)) {
                if(i == 1) {
                    rep(x1, 0, 1) rep(x2, 0, 1) {
                        if((x1 + x2) != (vis[j] + vis[j + 1])) continue;
                        dp[i][j][x1][x2] = ((x1 + x2) > 0 ? 1 : 0);
                    }
                }
                else {
                    rep(x1, 0, 1) rep(y1, 0, 1) rep(x2, 0, 1) rep(y2, 0, 1) {
                        ///x1,y1是从j开始连续的2^(i-1)个人比完后胜利者剩下的那个人的状态和失败组剩下的那个人的状态 (0:代表不是我喜欢的球队,1:代表是我喜欢的球队)
                        ///x2,y2是从j+(1<<(i-1))开始连续的2^(i-1)个人比完后剩下的那个人的状态和失败者剩下的那个人的状态
                        ///那么会有两次比赛,x1跟x2打,y1跟y2打,然后第二次有八种情况,逐个讨论
                        int res = dp[i - 1][j][x1][y1] + dp[i - 1][j + (1 << (i - 1))][x2][y2];
                        if(x1 || x2) res++; ///第一次比赛,先考虑
                        if(y1 || y2) res++;
                        
                        ///失败者最终胜利的是x2,那么有两种情况
                        dp[i][j][x1][x2] = max(dp[i][j][x1][x2], res + ( ( x2 + y1 > 0 ) ? 1 : 0 ) ); ///第一次比赛时失败组胜出的是y1,然后y1会跟x2再比一场
                        dp[i][j][x1][x2] = max(dp[i][j][x1][x2], res + ( ( x2 + y2 > 0 ) ? 1 : 0 ) ); ///第一次比赛时失败组胜出的是y2,然后y2会跟x2再比一场
    
                        /// 失败者最终胜利的分别是y1和y2,第一次比赛时胜利者胜出的是x1
                        dp[i][j][x1][y1] = max(dp[i][j][x1][y1], res + ( ( y1 + x2 > 0 ) ? 1 : 0 ) );///若第一次比赛y1胜出,y1会跟x2再比一场
                        dp[i][j][x1][y2] = max(dp[i][j][x1][y2], res + ( ( y2 + x2 > 0 ) ? 1 : 0 ) );///若第一次比赛y2胜出,y2会跟x2再比一场
                        
                        ///下同,只是换成了最终胜利的是x2
                        dp[i][j][x2][x1] = max(dp[i][j][x2][x1], res + ( ( x1 + y1 > 0 ) ? 1 : 0 ) );
                        dp[i][j][x2][x1] = max(dp[i][j][x2][x1], res + ( ( x1 + y2 > 0 ) ? 1 : 0 ) );
    
                        dp[i][j][x2][y1] = max(dp[i][j][x2][y1], res + ( ( y1 + x1 > 0 ) ? 1 : 0 ) );
                        dp[i][j][x2][y2] = max(dp[i][j][x2][y2], res + ( ( y2 + x1 > 0 ) ? 1 : 0 ) );
                    }
                }
            }
        }
    
        int ans = 0;
        rep(x1, 0, 1) rep(y1, 0, 1) {
            int res = dp[n][0][x1][y1];
            if(x1 || y1) res++;
            ans = max(ans, res);
        }
        printf("%d
    ", ans);
    
        return 0;
    }
    一步一步,永不停息
  • 相关阅读:
    【高级开发进阶】1.1.3 双亲委派模型及如何打破
    实战:第十七章:xlsx文件导入数据入库
    【高级开发进阶】6.1 现代计算机模型基础
    测试架构师必备技能Nginx安装部署实战
    还在为兼容性测试发愁?让我们用Python来轻松搞定吧
    Selenium经典面试题多窗口切换解决方案
    学会这些Jmeter插件,才能设计出复杂性能测试场景
    Pytest的高级用法,你get到了吗?
    是时候升级你的Junit了,Junit5超详细实战
    基于Jmeter实现Rocketmq消息发送
  • 原文地址:https://www.cnblogs.com/Willems/p/12376473.html
Copyright © 2020-2023  润新知