Double Elimination CodeForces - 1314B dp

∥☆過路亽.° 提交于 2020-03-16 09:01:51
//f[i,j,f1,f2]
//f1 和 f2 都是01数
//1表示剩下的人是喜欢的
//从j开始,长度为2^i个人,胜者组为f1,败者组为f2
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = ((1<<17)+1000);
int n,k,fans[maxn];
int dp[18][maxn][2][2];
//初始化 
void init() {
    for(int i=0; i<18; i++) {
        for(int j=0; j<maxn; j++) {
            for(int k=0; k<2; k++) {
                for(int z=0; z<2; z++) {
                    dp[i][j][k][z]=-1e9;
                }
            }
        }
    }
}
int main() {
    init();
    cin>>n>>k;
    for(int i=0; i<k; i++) {
        int x;
        cin>>x;
        fans[x-1]=1;
    }

    //枚举i
    for(int i=1; i<=n; i++) {
        //枚举人           区间长度
        for(int j=0; j<(1<<n); j+=(1<<i)) {
            //等于1,也就是初始化的时候
            if(i==1) {
                //表示状态
                // 比如说 1 和 2
                //可以1 胜 2 败
                //也可以2 胜 1 败
                for(int x1=0; x1<2; x1++) {
                    for(int y1=0; y1<2; y1++) {
                        //
                        if(x1+y1==fans[j]+fans[j+1]) {
                            //只要有一个是喜欢的,那么就有一场比赛
                            dp[i][j][x1][y1]=((fans[j]+fans[j+1])>0?1:0);
                        }
                    }
                }
            } else {
                //进行状态转移 合并
                //第一个胜者组状况和败者组状况
                for(int x1=0; x1<2; x1++) {
                    for(int y1=0; y1<2; y1++) {
                        //第二个胜者组状况和败者组状况
                        for(int x2=0; x2<2; x2++) {
                            for(int y2=0; y2<2; y2++) {
                                //一定是x1和x2比赛
                                //y1和y2比赛

                                //x1和x2比赛,要么x1输,要么x2输
                                //y1和y2比赛,要么y1输,要么y2输
                                //然后x1或者x2掉下来,再比赛
                                //那么一个就是八种

                                //原来两种的方案
                                int cost=dp[i-1][j][x1][y1]+dp[i-1][j+(1<<(i-1))][x2][y2];
                                //胜者组
                                if(x1||x2)
                                    cost++;
                                //败者组
                                if(y1||y2)
                                    cost++;
                                //直接暴力枚举这八种转移
                                //
                                dp[i][j][x1][x2]=max(dp[i][j][x1][x2],cost+((x2+y1)>0?1:0));
                                dp[i][j][x1][y1]=max(dp[i][j][x1][y1],cost+((x2+y1)>0?1:0));

                                dp[i][j][x1][x2]=max(dp[i][j][x1][x2],cost+((x2+y2)>0?1:0));
                                dp[i][j][x1][y2]=max(dp[i][j][x1][y2],cost+((x2+y2)>0?1:0));

                                dp[i][j][x2][x1]=max(dp[i][j][x2][x1],cost+((x1+y2)>0?1:0));
                                dp[i][j][x2][y2]=max(dp[i][j][x2][y2],cost+((x1+y2)>0?1:0));

                                dp[i][j][x2][x1]=max(dp[i][j][x2][x1],cost+((x1+y1)>0?1:0));
                                dp[i][j][x2][y1]=max(dp[i][j][x2][y1],cost+((x1+y1)>0?1:0));
                            }
                        }
                    }
                }
            }

        }
    }

    int ans = 0;
    for(int i=0; i<2; i++) {
        for(int j=0; j<2; j++) {
            int cost=dp[n][0][i][j];
            //再判断决赛,是否多看一场
            if(i+j>0)
                cost++;
            ans=max(ans,cost);
        }
    }
    cout<<ans<<endl;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!