Loading

GYM102155A A.Ability Draft 状压DP 博弈

GYM102155A A.Ability Draft 状压DP 博弈

题意

有两个阵营共\(2 \times n\)个英雄,每个英雄可以选择\(s\)个普通技能和\(1\)个终极技能。

两个阵容都希望自己的技能总和尽量大对方的尽量小,问最终的 阵容一 的和减去 阵容二的和

\[1 \leq n \leq 5,1 \leq s \leq 3 \]

分析

看数据范围容易想到状压DP

\(dp[i][j][k]\)表示前\(i\)个选择,\(j,k\)表示选择已经选择终极技能的情况

以开始的做法是从第1个开始枚举是否选择终极技能,然后往下递推,但很容易发现hack这样会走到很离谱的情况,于是想到这样的正确性可能不对,正确的应该是类似搜索那样从后往前DP

为了实现方便可以采取记忆化搜索(好像实现起来更烦)

据大佬口胡还可以用min-max搜索(待补)

代码

调了很久,实在是丑爆了

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
#define int long long
ll rd(){
	ll x = 0;
	int f = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9') {
		if(ch == '-') f = -1;
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9') {
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * f;
}


int dp[50][1 << 6][1 << 6];
int p[40];
int val1[100],val2[100];
int n,s;
int p1,p2;
int INF = 1e18;
// now = number of person haven't choose
// now1 = current position of normal
// now2 = current postion of specail
//

int get1(int x){
	if(x == INF) return -INF;
	return x;
}

int get2(int  x){
	if(x == -INF) return INF;
	return x;
}

int add(int x,int y){
	if(x == INF) return INF;
	if(x == -INF) return -INF;
	return x + y;
}

int dfs(int now,int msk1,int msk2,int now1,int now2){
	if(now == 2 * n * (s + 1)) return 0;
	if(now1 > 2 * n * s || now2 > 2 * n) return INF;
	if(dp[now][msk1][msk2] != INF && dp[now][msk1][msk2] != -INF) return dp[now][msk1][msk2];
	int ans;
	int ok;
	if(p[now] <= n) ok = (msk1 >> (p[now] - 1)) & 1;
	else ok = (msk2 >> (p[now] - n - 1)) & 1;
	ok ^= 1;
	ok |= (now2  >= 2 * n);
	int okk = (now1 >= 2 * n * s);
	if(p[now] <= n)  ans = max(max(-INF,ok ? -INF : add(get1(dfs(now + 1,msk1 ^ (1 << (p[now] - 1)),msk2,now1,now2 + 1)),val2[now2])),okk ?  -INF : add(get1(dfs(now + 1,msk1,msk2,now1 + 1,now2)) , val1[now1]));
	else {
		ans = min(min(INF,ok ? INF : add(get2(dfs(now + 1,msk1,msk2 ^ (1 << (p[now] - n - 1)),now1,now2 + 1)), - val2[now2])),okk ? INF : add(get2(dfs(now + 1,msk1,msk2,now1 + 1,now2)), -val1[now1]));
	}
	//cout << "now = " << now << " msk1 =  "<< msk1 << " msk2 = " << msk2 << " now1 = " << now1 << " now2 = " << now2 << " ok = " << ok << " okk = " << okk << "ans = " << ans << '\n';	
	return dp[now][msk1][msk2] = ans;
}

signed main(){
	n = rd();
	s = rd();
	for(int i = 0;i < 2 * n * (s + 1);i++)
		p[i] = rd();
	//reverse(p,p + 2 * n * (s + 1));
	p1 = rd();
	for(int i = 0;i < p1;i++)
		val1[i] = rd();
	p2 = rd();
	for(int i = 0;i < p2;i++)
		val2[i] = rd();
	for(int i = 0;i < 2 * n * (s + 1);i++){
		int f = p[i] <= n ? -INF : INF;
		for(int k = 0;k < (1 << 5);k++)
			for(int j = 0;j < (1 << 5);j++)
				dp[i][k][j] = f;
	}
	sort(val1,val1 + p1,greater<int>());
	sort(val2,val2 + p2,greater<int>());
	cout << dfs(0,(1 << n) - 1,(1 << n) - 1,0,0);
}

JianglyGG的代码

#include <bits/stdc++.h>
constexpr int N = 5, S = 3, T = 2 * N * (S + 1), INF = 1e9;
int n, s, pu, ps;
int p[T], vs[36], vu[12], dp[T + 1][1 << (2 * N)], ok[T + 1][1 << (2 * S)];
int main() {
    std::srand(std::chrono::steady_clock::now().time_since_epoch().count());
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cin >> n >> s;
    for (int i = 0; i < 2 * n * (s + 1); ++i) {
        std::cin >> p[i];
        --p[i];
    }
    std::cin >> ps;
    for (int i = 0; i < ps; ++i)
        std::cin >> vs[i];
    std::cin >> pu;
    for (int i = 0; i < pu; ++i)
        std::cin >> vu[i];
    std::sort(vs, vs + ps, std::greater<>());
    std::sort(vu, vu + pu, std::greater<>());
    ok[2 * n * (s + 1)][(1 << (2 * n)) - 1] = 1;
    for (int i = 2 * n * (s + 1) - 1; i >= 0; --i) {
        for (int j = 0; j < (1 << (2 * n)); ++j) {
            int c = __builtin_popcount(j);
            ok[i][j] = ok[i + 1][j] | ok[i + 1][j | 1 << p[i]];
            if (!ok[i][j] || c > i)
                continue;
            if (p[i] < n) {
                dp[i][j] = std::max(ok[i + 1][j] ? dp[i + 1][j] + vs[i - c] : -INF, (~j >> p[i] & 1) && ok[i + 1][j | 1 << p[i]] ? dp[i + 1][j | 1 << p[i]] + vu[c] : -INF);
            } else {
                dp[i][j] = std::min(ok[i + 1][j] ? dp[i + 1][j] - vs[i - c] : INF, (~j >> p[i] & 1) && ok[i + 1][j | 1 << p[i]] ? dp[i + 1][j | 1 << p[i]] - vu[c] : INF);
            }
        }
    }
    std::cout << dp[0][0] << "\n";
    return 0;
}
posted @ 2021-07-17 18:46  MQFLLY  阅读(61)  评论(0编辑  收藏  举报