Ban or Pick, What’s the Trick
https://codeforces.com/gym/104065/problem/A
记忆化搜索例题,
由于是轮流制,而且轮到A或B时,只能选择ban或者选英雄,那么,如果选肯定优先选己方最大的,如果禁,肯定禁对方最大的,由此,我们需要对两个英雄池进行降序排序。
根据需求我们可得转移方程
对于A希望,拉的分查越大越好
max(选择了英雄,没有选择英雄)
对于B希望,拉的分查越小越好
min(选择了英雄,没有选择英雄)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2*1e5+10;
const ll K = 12;
ll dp[N][K][K];
ll a[N/2],b[N/2];
ll n,k;
const ll inf =-(1e17+10);
void init(ll n,ll k){
for(ll i=0;i<=n;i++){
for(ll j=0;j<=k;j++){
for(ll z=0;z<=k;z++){
dp[i][j][z]=inf;
}
}
}
}
// turn是目前轮流的次数,ta是A队选择了ta个英雄,tb是B队选择了tb个英雄
ll dfs(ll turn,ll ta,ll tb){
if(turn ==2*n) return 0;
//记忆化搜索的关键,避免重复计算。使得指数的时间复杂度缩减为O(n);
if(dp[turn][ta][tb]!=inf) return dp[turn][ta][tb];
//pa pb 分别表示为确认a目前英雄池判断英雄所在的位置,b也是一样的道理
//根究轮次和两队分别选择的英雄数量,判断pa,pb要判断英雄的位置。
ll pa=turn/2 + ta-tb;
ll pb=(turn+1)/2+tb-ta;
if(turn%2){
//轮到B进行选择
ll res = -inf;
//如果B能够进行选择英雄
if(ta+tb<=2*n&&tb<k){
res = min(res,dfs(turn+1,ta,tb+1)-b[pb+1]);
}
//与B不能够进行选择英雄进行判断
res = min(res,dfs(turn+1,ta,tb));
//记住选择
dp[turn][ta][tb] = res;
return res;
}
else{
//轮到A进行选择。
ll res = inf;
//如果A能够进行选择英雄
if(ta+tb<=2*n&&ta<k){
res = max(res,dfs(turn+1,ta+1,tb)+a[pa+1]);
}
//与A不能够进行选择英雄进行判断
res = max(res,dfs(turn+1,ta,tb));
//记住选择
dp[turn][ta][tb] = res;
// cout<<res<<" "<<turn<<endl;
return res;
}
}
signed main(){
cin>>n>>k;
for(ll i=1;i<=n;i++) cin>>a[i];
for(ll i=1;i<=n;i++) cin>>b[i];
init(n*2,k);
sort(a+1,a+n+1,greater<ll>());
sort(b+1,b+n+1,greater<ll>());
cout<<dfs(0,0,0);
}