• 1315E Double Elimination DP 01枚举状态和倍增思想


    E. Double Elimination DP 01枚举状态和倍增思想

    题意

    参考DOTA2双败赛制,一共有(2^n)个队打n轮 其中你有k喜欢的队伍,由你掌控比赛的输赢请问比赛中包含你喜欢的队伍的场次最多有多少场

    思路

    看数据就很DP,但是比赛的时候不知道怎么搞。其实喜欢队伍与否就是一个01状态,每一场比赛的都会尝生一个胜利队伍和一个失败队伍,把这个胜利和失败队伍去和相邻的胜利和失败的队伍去比就会另外一个胜利和失败的队伍,这样就可以用倍增的思想去定义状态。

    我们定状态为(dp[i][j][x][y])从j出发长度为(2^i)的比赛队伍产生的胜者队伍是否为关注的队伍,x=1表示是,0表示不是,败者队伍同理那么转移就可以很方便得列举出来。

    转移为 (dp[i-1][j][x1][y1])(dp[i-1][j+(1<<(i-1))][x2][y2])进行比赛,列举他们的状态进行合并,首先是x1和x1比以及y1和y2比 这样关注的队伍的比赛场次为(dp[i-1][j][x1][y1]+dp[i-1][j+(1<<(i-1))][x2][y2]+int(x1||x2)+int(y1||y2))以及还要根据比赛的具体结果看决出败者的时候是否有关注的队伍,有就要加1,一共8种状态,可以画图找一找

    这样复杂度就是(O(2^{17}*17*8*8))

    本地只要想到把喜欢与否转变为01状态并且有倍增的思想,那么列出状态后进行转移就相对较为简单,初始化的时候需要把所以dp值初始化成一个非常小的数字,防止进行非法转移,刚开始设置成-1 发生了非法转移样例1都过不去QAQ

    #include<bits/stdc++.h>
    #define pb push_back
    #define mkp make_pair
    using namespace std;
    typedef long long ll;
    const int mod=1e9+7;
    const int maxn=(1<<17)+1;
    int dp[17][maxn][2][2];
    int vis[maxn];
    int n,k;
    void init(){
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<(1<<n);j+=(1<<i)){
    			for(int x=0;x<2;x++)
    				for(int y=0;y<2;y++)dp[i][j][x][y]=-maxn;
    		}
    	}
    }
    int main(){
    	scanf("%d%d",&n,&k);
    	for(int i=1;i<=k;i++){
    		int x;
    		scanf("%d",&x);
    		vis[x-1]=1;
    	}
    	//memset(dp,-1,sizeof(dp));
    	init();
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<(1<<n);j+=(1<<i)){
    			if(i==1){
    				for(int x1=0;x1<2;x1++){
    					for(int y1=0;y1<2;y1++){
    						if(vis[j]+vis[j+1]==x1+y1){
    							dp[i][j][x1][y1]=(vis[j]+vis[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++){
    								int num=dp[i-1][j][x1][y1]+dp[i-1][j+(1<<(i-1))][x2][y2];
    								if(x1||x2)num++;
    								if(y1||y2)num++;
    								dp[i][j][x1][y1]=max(dp[i][j][x1][y1],num+((x2+y1)>0?1:0));
    								dp[i][j][x1][y2]=max(dp[i][j][x1][y2],num+((x2+y2)>0?1:0));
    								
    								dp[i][j][x2][y1]=max(dp[i][j][x2][y1],num+((x1+y1)>0?1:0));
    								dp[i][j][x2][y2]=max(dp[i][j][x2][y2],num+((x1+y2)>0?1:0));
    								
    								dp[i][j][x1][x2]=max(dp[i][j][x1][x2],num+((x2+y1)>0?1:0));
    								dp[i][j][x1][x2]=max(dp[i][j][x1][x2],num+((x2+y2)>0?1:0));
    
    								dp[i][j][x2][x1]=max(dp[i][j][x2][x1],num+((x1+y1)>0?1:0));
    								dp[i][j][x2][x1]=max(dp[i][j][x2][x1],num+((x1+y2)>0?1:0));
    							}
    						}
    					}
    				}
    			}
    		}
    	}
    	int ans=0;
    	for(int i=0;i<2;i++){
    		for(int j=0;j<2;j++){
    			ans=max(ans,dp[n][0][i][j]+(i+j>0?1:0));
    		}
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
    

    最后感谢qscqesze的题解,感兴趣的可以去B站直接搜这个名字哦

  • 相关阅读:
    BZOJ 1726: [Usaco2006 Nov]Roadblocks第二短路
    BZOJ 1708: [Usaco2007 Oct]Money奶牛的硬币
    BZOJ 1642: [Usaco2007 Nov]Milking Time 挤奶时间
    BZOJ 1611: [Usaco2008 Feb]Meteor Shower流星雨
    BZOJ 1610: [Usaco2008 Feb]Line连线游戏
    BZOJ 1609: [Usaco2008 Feb]Eating Together麻烦的聚餐
    BZOJ 1607: [Usaco2008 Dec]Patting Heads 轻拍牛头
    BZOJ 1606: [Usaco2008 Dec]Hay For Sale 购买干草
    BZOJ 1083: [SCOI2005]繁忙的都市
    STL set的用法
  • 原文地址:https://www.cnblogs.com/ttttttttrx/p/12373135.html
Copyright © 2020-2023  润新知