游戏

题意

给定一个集合 S,|S|=n

m 轮操作,两人交替操作。

每一轮有一个参数 b,每次进行两种操作:保留 S 中满足 bx 的数或保留 S 中满足 bx 的数。

先手希望最终 S 内元素总和尽可能小,后手希望尽可能大。

问两人都采取最优策略,最终的值是多少。

思路

在这之前,我一直都不知道博弈论的题怎么写暴力。

这道题其实就是爆搜即可。

对于每一步,我们都搜可能的两种状态,然后当前层如果是先手,接受较小的;后手,接受较大的。

如果哪个集合没有东西了,直接返回 0

一共 m 层,由于没有东西直接 return 了,所以每一层都是 n 个数,复杂度 O(nm)

实际上,当 m>2lgn 时,答案就是 0

先手每一次都会使得集合大小减半,最后一定会变成 0,考虑交替操作,所以结果 0,对于后者,同理,0,所以 =0

#include<iostream>
#include<vector>
using namespace std;
const int N=20010,M=30;
typedef long long ll;
const ll INF=1e18;
int n,m,cnt;
ll b[M];
ll dfs(vector<ll>&a,int d){
	vector<ll>t1,t2;
	++cnt;
	// printf("node=%d,dep=%d\n",cnt,d);
	ll s1=INF,s2=INF;
	for(ll v:a)
		if(v%b[d]==0)t1.push_back(v);
		else t2.push_back(v);
	// printf("div by %lld,s1=%lld\n",b[d],s1);
	// for(ll v:t1)printf("%d ",v);
	// puts("\nother");
	// for(ll v:t2)printf("%d ",v);
	// puts("\n\n\n");
	if(t1.empty())s1=0;
	if(t2.empty())s2=0;
	if(d==m){
		s1=s2=0;
		for(ll v:t1)s1+=v;
		for(ll v:t2)s2+=v;
		return d&1?min(s1,s2):max(s1,s2);
	}
	if(s1==INF)s1=dfs(t1,d+1);
	if(s2==INF)s2=dfs(t2,d+1);
	return d&1?min(s1,s2):max(s1,s2);
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m;
	if(m>28){
		putchar('0');
		return 0;
	}
	vector<ll>a(n);
	for(ll &v:a)cin>>v;
	for(int i=1;i<=m;++i)cin>>b[i];
	cout<<dfs(a,1);
	// dfs(a,1);
	return 0;
}

本文作者:wscqwq

本文链接:https://www.cnblogs.com/wscqwq/p/17768069.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   wscqwq  阅读(7)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起