Remove Numbers (博弈,复杂度证明)

题意

给定数组a,b,第i回合,玩家可以删掉所有的j, g c d ( b i , a j ) ≠ 1 gcd(b_i,a_j)\neq1 gcd(bi,aj)=1,或所有 g c d ( b i , a j ) = 1 gcd(b_i,a_j)=1 gcd(bi,aj)=1。先手玩家要使得和最大,后手要使得和最小。

constrains:
1 ≤ n ≤ 2 e 4 1\leq n\leq 2e4 1n2e4
1 ≤ m ≤ 2 e 5 1\leq m\leq 2e5 1m2e5
− 4 e 14 ≤ a i ≤ 4 e 14 -4e14\leq a_i\leq4e14 4e14ai4e14

思路

想了半天不知道怎么dp,感觉只能minmax搜索。
容易观察到一个性质是,如果 a i > 0 a_i>0 ai>0,Alice每次操作至少可以折半,就是说 m > 150 m>150 m>150时,结果必为0, a i < 0 a_i<0 ai<0,Bob也同理。
但当时我在想两个人尬住会咋样,没仔细证明尬住最终也会归0。
有这个还不够,直接搜索 2 150 2^{150} 2150,看了别人的提交,似乎利用了每论先后手删除,长度至少折半?数组没了直接return,深度不会超过 O ( l o g n ) O(logn) O(logn)

这种题真得大胆猜,大胆举例分析。

代码

#include<bits/stdc++.h>
using namespace std;
#define pow2(X) (1ll<<(X))
#define SIZE(A) ((int)A.size())
#define LENGTH(A) ((int)A.length())
#define ALL(A) A.begin(),A.end()
#define F(i,a,b) for(ll i=a;i<=(b);++i)
#define dF(i,a,b) for(ll i=a;i>=(b);--i)
#define GETPOS(c,x) (lower_bound(ALL(c),x)-c.begin())
#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3f
#define pb push_back
#define pr pair<int,int>
#define mkp make_pair
#define fi first
#define se second
#define eps 1e-6
#define PI acos(-1.0)
#define lb lower_bound
#define ub upper_bound
#define bs binary_search
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
#define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ];void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;}void adde(int a,int b){ad_de(a,b);ad_de(b,a);}
#define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ];void ad_de(int a,int b,int c){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);}
#define es(x,e) (int e=fst[x];e;e=nxt[e])
#define esb(x,e,b) (int e=fst[x],b=vb[e];e;e=nxt[e],b=vb[e])
#define SZ 666666
typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> ipair;
typedef vector<int> VI;
typedef vector<long long> VLL;
typedef vector<vector<long long > > VVLL;
typedef vector<vector<int> > VVI;
typedef vector<double> VD;
typedef vector<string> VS;
const int mods = 998244353;
//const int mods = 1e9+7;
const int maxn = 2e5+10;
const int N = 5e5+10;
const int E = 1e4+10;
const int lim = 1e9;
ll qpow(ll a,ll b) {ll res=1;a%=mods; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mods;a=a*a%mods;}return res;}
ll lcm(ll a, ll b) {return a / __gcd(a, b) * b;}
int read(){ll x=0,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;}

ll n,m,k;
VLL a,b;
ll ans;
ll dfs(int j,ll s,VLL &x){
    if(j==m+1){
		return s;
	}
    if(x.size()==0) return 0;
	VLL c;
	VLL d;
	ll res = 0;
	for(auto ss:x){
	    if(ss==0) continue;
		if(ss%b[j]==0){
			c.pb(ss);
			res+=ss;
		}
		else d.pb(ss);
	}
	ll tmp1 = dfs(j+1,res,c);
	ll tmp2 = dfs(j+1,s-res,d);

	if(j&1) return min(tmp1,tmp2);
	else return max(tmp1,tmp2);
}

int main(){
	// freopen("C:\\Users\\Gao\\Desktop\\validation_input\\watering_well_chapter_2_input.txt","r",stdin);
	// freopen("C:\\Users\\Gao\\Desktop\\validation_input\\output.txt","w",stdout);
	ios_base::sync_with_stdio(0);
    int T;
    //cin>>T; 
	T = 1;
	F(turn,1,T){
		cin>>n>>m;
		ll sum = 0;
		ans = infll;
		a.resize(n+1,0);
		b.resize(m+1,0);
		F(i,1,n){
			cin>>a[i];
			sum+=a[i];
		}
		F(i,1,m){
			cin>>b[i];
		}
		if(m>150){
		    cout<<"0\n";
		    break;
		}
		
		ans = dfs(1,sum,a);

		cout<<ans<<endl;
	}
}
 
/*
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值