返回顶部

[AGC056D] Subset Sum Game

[AGC056D] Subset Sum Game

题面翻译

一块黑板上写着 \(n\) 个整数。第 \(i\) 个整数记作 \(a_i\)。保证 \(n\) 是偶数。此外,给定 \(L,R\)

Alice 和 Bob 在玩一个游戏。他们轮流操作,Alice 先手。在每一轮中,玩家需要选择一个写在黑板上的数,并擦掉它。

游戏会在 \(n\) 轮后结束。令 \(s\) 为 Alice 擦掉的数之和。若 \(L \le s \le R\),则 Alice 胜利,反之 Bob 胜利。你需要输出当两方都采取最优策略情况下的赢家。

\(2\le n\le 5000,\ 1\le a_i\le 10^9, 0\le L \le R \le \sum_{1\le i\le n} a_i\)

题目描述

黒板に $ N $ 個の整数が書かれており,そのうち $ i $ 番目の整数は $ A_i $ です. なお,$ N $ は偶数です. また,整数 $ L,R $ が与えられます.

Alice と Bob がゲームをします. 二人は Alice からはじめて交互に手番をプレイします. 各手番では,プレイヤーは黒板に書かれている数を一つ選んで消します.

$ N $ ターン後にゲームが終了します. ここで,Alice が消した整数の総和を $ s $ とします. $ L\ \leq\ s\ \leq\ R $ であれば Alice の勝利,そうでなければ Bob の勝利です. 両者が最適に行動した時,どちらが勝つか求めてください.

输入格式

入力は以下の形式で標準入力から与えられる.

$ N $ $ L $ $ R $ $ A_1 $ $ A_2 $ $ \cdots $ $ A_N $

输出格式

Alice が勝つ場合は Alice,Bob が勝つ場合は Bob と出力せよ.

样例 #1

样例输入 #1

4 5 6
3 1 4 5

样例输出 #1

Alice

样例 #2

样例输入 #2

2 2 3
4 1

样例输出 #2

Bob

样例 #3

样例输入 #3

30 655 688
42 95 9 13 91 27 99 56 64 15 3 11 5 16 85 3 62 100 64 79 1 70 8 69 70 28 78 4 33 12

样例输出 #3

Bob

样例 #4

样例输入 #4

30 792 826
81 60 86 57 5 20 26 13 39 64 89 58 43 98 50 79 58 21 27 68 46 47 45 85 88 5 82 90 74 57

样例输出 #4

Alice

提示

制約

  • $ 2\ \leq\ N\ \leq\ 5000 $
  • $ N $ は偶数
  • $ 1\ \leq\ A_i\ \leq\ 10^9 $
  • $ 0\ \leq\ L\ \leq\ R\ \leq\ \sum_{1\ \leq\ i\ \leq\ N}\ A_i $
  • 入力される値はすべて整数である

Sample Explanation 1

このゲームでは Alice が必ず勝ちます. ゲームの進行の一例を以下に示します. - Alice が $ 1 $ を消す. - Bob が $ 4 $ を消す. - Alice が $ 5 $ を消す. - Bob が $ 3 $ を消す. この時,Alice が消した整数の総和は $ 6 $ であり,$ L\ \leq\ 6\ \leq\ R $ なので,Alice の勝利です.

这题是道博弈论黑题,看似毫无落脚点,那我们首先转移题意,设\(S_a\)\(Alice\)擦掉的总数和,\(S_b\)\(Bob\)擦掉的总数和,设\(S\)为所有数的和。题目要求\(L<=S_a<=R\)
那我们可以转换为\(2L<=2S_a<=2R\)
\(2L-S<=2S_a-S<=2R-S\)
\(2L-S<=S_A-S_B<=2R-S\)
\(x=S-(L+R)\)
则原式为\(L-R<=S_a-S_B+x<=R-L\)即为\(|S_a-S_B+x|<=R-L\)

这时候,题意就转换完了
题意转换为,给定整数\(x\),\(Alice\)一次操作,使得\(x'=S-(R+L-a_i)=x+a_i\),则\(Bob\)\(X-a_i\)
\(Alice\)想让\(x\)尽量小,\(Bob\)想让\(x\)尽量大,问谁赢?
记一个长为\(m\)序列\(b_i\)的相邻项差分\(diffb=(b_2-b_1)+(b_4-b_3)+...+(b_m-b_{m-1})\)
假设\(a_i\)升序排列。推断,最终的分数可以通过如下方式求得:

  • 选择整数\(p\),将\(p,p+x,a_1,a_2,...,a_n\)升序得到\(A_i\),令\(p\)的答案为\(diff A\)的值
  • 最终的分数即为所有可能的\(p\)的答案中的最小值

膜拜

复杂度为\(O(n^2)\)

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define lid (rt<<1)
#define rid (rt<<1|1)
#define endl '\n'
//#define int long long
#define pb push_back
using namespace std;
const int N = 5005;
ll n,l,r,a[N];
int main()
{
	speed();
	int T;
	cin>>T;
//	T=1;
	while(T--)
	{
		cin>>n>>l>>r;
		ll s=0;
		for(int i=1;i<=n;i++)cin>>a[i],s+=a[i];
		s-=(l+r);
		sort(a+1,a+1+n);
		vector <ll> p;
		ll ans=LLONG_MAX;
		for(int i=1;i<=n;i++)
		{
			ll tmp=0;
			p.clear();
			for(int j=1;j<=n;j++)
			{
				if(i==j)continue;
				p.pb(a[j]);
			}
			p.insert(lower_bound(p.begin(),p.end(),a[i]+s),a[i]+s);
			for(int i=n-1;i>=0;i-=2)tmp+=(p[i]-p[i-1]);
			ans=min(ans,abs(tmp));
		}
//		cout<<abs(ans)<<endl;
		if(abs(ans)<=r-l)cout<<"Alice"<<endl;
		else cout<<"Bob"<<endl;
	}
	return 0;
}
posted @ 2024-07-26 20:08  wlesq  阅读(11)  评论(0编辑  收藏  举报