本文主要是介绍Codeforces 1310 B Double Elimination —— 记忆化搜索,有丶东西,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
This way
题意:
现在有 2 n 2^n 2n个队伍,第一次每相邻两个队伍比赛,然后剩下 2 n − 1 2^{n-1} 2n−1个胜利者和 2 n − 1 2^{n-1} 2n−1个loser,胜利者会进行下一场比赛,同时loser也会进行下一场比赛,然后对于这次胜利者淘汰下来的 2 n − 2 2^{n-2} 2n−2个人,加上loser中的 2 n − 2 2^{n-2} 2n−2个人,又进行一场比赛,然后循环这个操作,直到最后一个胜利者和最后一个loser,他们会进行一次决斗。
你有一些喜欢的人,给你这些人的编号,你可以任意指定每一个人每一局的输赢使得所有比赛中包含你喜欢的人出场的比赛最多,问你最多是多少。
题解:
我看了有很多解法,但是我一个都想不出来,我选了记忆化搜索来理解,dp[x][l][r]表示在l到r这个区间最终赢的赢和输的赢的状态为x时答案最大是多少。因为败方比赛会有两次,所以可以直接用2表示败方是否有。
那么状态转移就是两个子区间的和,枚举左区间和右区间的情况。
((i&2)|(i<<1)|j)&3
这里我也理解了一会,这种情况是i的胜败了,i&2表示i的败方是否有喜欢的队伍,i<<1表示i的胜方到败方时是否有喜欢的队伍。
#include<bits/stdc++.h>
using namespace std;
const int N=(1<<17)+5;
unordered_map<int,int>mp[4][N];
bool fav[N];
int dfs(int l,int r,int s){//01:赢得赢 10:输的赢if(r==l+1){int num1=fav[l]+fav[r],num2=(s&1)+(s>>1);if(num1==num2)return min(1,num2);elsereturn -1e6;}if(mp[s][l].count(r))return mp[s][l][r];int ans=-1e6,mid=l+r>>1;for(int i=0;i<4;i++){for(int j=0;j<4;j++){int ilose=((i&2)|(i<<1)|j)&3,jlose=((j&2)|(j<<1)|i)&3;if(ilose==s||jlose==s)ans=max(ans,dfs(l,mid,i)+dfs(mid+1,r,j));}}return mp[s][l][r]=ans+s;
}
int main()
{int n,m,x;scanf("%d%d",&n,&m);for(int i=1;i<=m;i++)scanf("%d",&x),fav[x]=1;int ans=0;for(int i=0;i<4;i++)ans=max(ans,dfs(1,1<<n,i));printf("%d\n",ans+(m?1:0));//最后赢和输还有一场对决return 0;
}
这篇关于Codeforces 1310 B Double Elimination —— 记忆化搜索,有丶东西的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!