[Codeforces] games (R1200) Part.2
题单:https://codeforces.com/problemset?tags=games,0-1200
1270A. Card Game
原题指路:https://codeforces.com/problemset/problem/1270/A
题意
有编号 1 ∼ n 1\sim n 1∼n的 n n n张卡,每张卡有一个权值,卡的权值两两相异.A和B玩游戏,A先手.初始时所有的卡分配到A和B手中.每轮每人从手中的卡选一张倒扣在桌面上(对手看不见),两人都放完后揭晓卡,卡权值较大的人将两张卡都拿走.手中无卡者负.现给定初始时A和B手中的卡,两人都采取最优策略,若A必胜则输出"YES";否则输出"NO".
有 t ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t (1≤t≤100)组测试数据.每组测试数据第一行输入三个整数 n , k 1 , k 2 ( 2 ≤ n ≤ 100 , 1 ≤ k 1 ≤ n − 1 , 1 ≤ k 2 ≤ n − 1 , k 1 + k 2 = n ) n,k_1,k_2\ \ (2\leq n\leq 100,1\leq k_1\leq n-1,1\leq k_2\leq n-1,k_1+k_2=n) n,k1,k2 (2≤n≤100,1≤k1≤n−1,1≤k2≤n−1,k1+k2=n),分别表示卡总数、初始时A手中的卡数、初始时B手中的卡数.第二行输入 k 1 k_1 k1个整数 a 1 , ⋯ , a k 1 ( 1 ≤ a i ≤ n ) a_1,\cdots,a_{k_1}\ \ (1\leq a_i\leq n) a1,⋯,ak1 (1≤ai≤n),表示初始时A手中的卡的权值.第三行输入 k 2 k_2 k2个整数 b 1 , ⋯ , b k 2 ( 1 ≤ b i ≤ n ) b_1,\cdots,b_{k_2}\ \ (1\leq b_i\leq n) b1,⋯,bk2 (1≤bi≤n),表示初始时B手中的卡的权值.数据保证所有卡的权值两两相异.
思路
显然有最大权值卡的人每次都出该卡即可必胜.
代码
void solve() {
int n, k1, k2; cin >> n >> k1 >> k2;
bool ok = false;
while (k1--) {
int a; cin >> a;
ok |= a == n;
}
while (k2--) {
int a; cin >> a;
}
cout << (ok ? "YES" : "NO") << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1365A. Matrix Game
原题指路:https://codeforces.com/problemset/problem/1365/A
题意
给定一个 n × m n\times m n×m的 0 − 1 0-1 0−1矩阵,其中 0 0 0表示该格子未被染色, 1 1 1表示该格子被染色.Ashish和Vivek轮流给矩阵染色Ashish先手.染色要求要染色的格子与已染色的格子不在同一行和同一列.两人都采取最优策略,问最后谁胜.
有 t ( 1 ≤ t ≤ 50 ) t\ \ (1\leq t\leq 50) t (1≤t≤50)组测试数据.每组测试数据第一行输入两个整数 n , m ( 1 ≤ n , m ≤ 50 ) n,m\ \ (1\leq n,m\leq 50) n,m (1≤n,m≤50).第二行输入一个 n × m n\times m n×m的 0 − 1 0-1 0−1矩阵.
思路
设未被染色的行数为 a a a,列数为 b b b,则游戏会进行 min { a , b } \min\{a,b\} min{a,b}步,判断其奇偶即可.
代码
void solve() {
int n, m; cin >> n >> m;
vector<vi> a(n, vi(m));
uset<int> row, col;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> a[i][j];
if (a[i][j]) row.insert(i), col.insert(j);
}
}
int ans = min(n - row.size(), m - col.size());
cout << (ans & 1 ? "Ashish" : "Vivek") << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1373B. 01 Game
原题指路:https://codeforces.com/problemset/problem/1373/B
题意
给定一个 0 − 1 0-1 0−1串 s s s.Alice和Bob轮流操作,Alice先手.每轮每人选 s s s中的两个相邻且相异的字符,将它们删去,无法操作者负.两人都采取最优策略,若Alice胜则输出"DA";否则输出"NET".
思路
若当前 s s s中至少存在一个 0 0 0且至少存在一个 1 1 1,则玩家都能操作,故操作次数为 min { c n t 0 , c n t 1 } \min\{cnt_0,cnt_1\} min{cnt0,cnt1},其中 c n t 0 cnt_0 cnt0、 c n t 1 cnt_1 cnt1分别为 s s s中 0 0 0、 1 1 1的个数,判断其奇偶即可.
代码
void solve() {
string s; cin >> s;
cout << (min(count(all(s), '0'), (int)s.length() - count(all(s), '0')) & 1 ? "DA" : "NET") << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1382B. Sequential Nim
原题指路:https://codeforces.com/problemset/problem/1382/B
题意
编号 1 ∼ n 1\sim n 1∼n的 n n n堆石头排成一行,其中第 i i i堆有 a i a_i ai个石头.A和B轮流操作,A先手.每轮每人从最左边的第一堆非空的石头中取走至少一个石头,无法操作者负.两人都采取最优策略,若最后A胜则输出"Firtst";否则输出"Second".
有 t ( 1 ≤ t ≤ 1000 ) t\ \ (1\leq t\leq 1000) t (1≤t≤1000)组测试数据.每组测试数据第一行输入一个整数 n ( 1 ≤ n ≤ 1 e 5 ) n\ \ (1\leq n\leq 1\mathrm{e}5) n (1≤n≤1e5).第二行输入 n n n个整数 a 1 , ⋯ , a n ( 1 ≤ a i ≤ 1 e 9 ) a_1,\cdots,a_n\ \ (1\leq a_i\leq 1\mathrm{e}9) a1,⋯,an (1≤ai≤1e9).数据保证所有测试数据的 n n n之和不超过 1 e 5 1\mathrm{e}5 1e5.
思路
①若 a 1 = 1 a_1=1 a1=1,则A只能取完第一堆.
②若 a 1 > 1 a_1>1 a1>1,若取完整堆能获胜,则A取完整堆;否则A会取到该堆只剩下一个石头,让B只能取完第一堆.
综上,现取到有 > 1 >1 >1个石头的堆的玩家获胜.设 k k k是最大的下标 s . t . a 1 = ⋯ = a k = 1 \ s.t.\ a_1=\cdots=a_k=1 s.t. a1=⋯=ak=1.
①若 k k k是偶数,则先手胜;否则后手胜.
②若所有堆都只有一个石头,则先手必胜当且仅当 k k k是奇数.
代码
void solve() {
int n; cin >> n;
vi a(n);
for (auto& ai : a) cin >> ai;
int k = 0;
while (k < n && a[k] == 1) k++;
cout << ((k == n) ^ (k & 1) ? "Second" : "First") << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1398B. Substring Removal Game
原题指路:https://codeforces.com/problemset/problem/1398/B
题意 ( 2 s 2\ \mathrm{s} 2 s)
给定一个 0 − 1 0-1 0−1串 s s s.Alice和Bob轮流操作,Alice先手.每轮每人选择一段非空的连续相同的字符,将它们删去,当 s s s为空时游戏结束.每人的得分为他删去的 1 1 1的个数.若两人都想最大化自己的得分,求Alice的最大得分.
有 t ( 1 ≤ t ≤ 500 ) t\ \ (1\leq t\leq 500) t (1≤t≤500)组测试数据.每组测试数据输入一个 0 − 1 0-1 0−1串 s ( 1 ≤ ∣ s ∣ ≤ 100 ) s\ \ (1\leq |s|\leq 100) s (1≤∣s∣≤100).
思路
最优策略:每人每轮选当前最长的连续 1 1 1,将其删去.
[证] (1)只删除最长的连续 1 1 1的一部分不是最优策略,这会导致自己的得分减小,对手的得分增多.
(2)无需删除 0 0 0.
①若只删除连续 0 0 0的一部分,则不会增加双方的分数,但是自己会浪费一次得分的机会.
②若删除整段连续 0 0 0,则会使得两边的 1 1 1连在一起,这会导致对手得分可能增多.
预处理出 s s s中连续 1 1 1的长度,将其降序排序后Alice取奇数下标即可.
代码
void solve() {
string s; cin >> s;
vi len;
for (int i = 0; s[i]; i++) {
if (s[i] == '1') {
int j = i;
while (j + 1 < s.length() && s[j + 1] == '1') j++;
len.push_back(j - i + 1);
i = j;
}
}
sort(rall(len));
int ans = 0;
for (int i = 0; i < len.size(); i += 2) ans += len[i];
cout << ans << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1419A. Digit Game
原题指路:https://codeforces.com/problemset/problem/1419/A
题意
A和B玩游戏,A先手.初始时给定一个长度为 n n n的整数 x x x,从高位到低位依次编号 1 ∼ n 1\sim n 1∼n.每轮每人选一个当前未被标记的位置将其标记,轮到A时,他只能选择奇数下标的位置;轮到B时,他只能选择偶数下标的位置.当只剩下一个未被标记的位置时游戏结束,此时若剩下的数字为奇数,则A胜;否则B胜.两人都采取最优策略,若最后A胜,输出 1 1 1;否则输出 2 2 2.
有 t ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t (1≤t≤100)组测试数据.每组测试数据第一行输入一个整数 n ( 1 ≤ n ≤ 1000 ) n\ \ (1\leq n\leq 1000) n (1≤n≤1000).第二行输入一个 n n n位的整数.
思路
①若 n n n为偶数,则最后一个未被标记的位置的下标为偶数.
若至少存在一个下标为偶数的偶数数码 y y y,则B胜,因为他可标记除 y y y外的所有偶数下标的位置,最后剩下 y y y;
否则A胜,因为最后剩下的数码都是奇数.
②若 n n n为奇数,则最后一个未被标记的位置的下标为奇数.
若至少存在一个下标为奇数的奇数数码 z z z,则A必胜;否则B必胜.
代码
const int MAXN = 1005;
int n;
char s[MAXN];
void solve() {
cin >> n >> s + 1;
bool odd = false; // 是否存在下标为奇数的奇数数码
bool even = false; // 是否存在下标为偶数的偶数数码
for (int i = 1; i <= n; i++) {
if (i & 1) odd |= (s[i] - '0') % 2 == 1;
else even |= (s[i] - '0') % 2 == 0;
}
if (n & 1) cout << (odd ? 1 : 2) << endl;
else cout << (even ? 2 : 1) << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1455C. Ping-pong
原题指路:https://codeforces.com/problemset/problem/1455/C
题意
A和B打乒乓球,A先手.初始时A和B分别有 x x x、 y y y的体力.每轮游戏发球者必须消耗 1 1 1点体力发球;接球者可选择消耗 1 1 1点体力接球,也可选择不接球并输掉该轮.该轮的胜者下一轮发球.两玩家的体力都为 0 0 0时游戏结束.A和B都想最大化自己胜的场数,同时最小化对手胜的场数,两人都采取最优策略,问各自胜的场数.
有 t ( 1 ≤ t ≤ 1 e 4 ) t\ \ (1\leq t\leq 1\mathrm{e}4) t (1≤t≤1e4)组测试数据.每组测试数据输入两个整数 x , y ( 1 ≤ x , y ≤ 1 e 6 ) x,y\ \ (1\leq x,y\leq 1\mathrm{e}6) x,y (1≤x,y≤1e6).
思路
设A初始体力为 x x x、B初始体力为 y y y时两人各自胜的场数为 f ( x , y ) f(x,y) f(x,y).
(1)显然 f ( 0 , x ) = ( 0 , x ) , f ( x , 0 ) = f ( x , 0 ) f(0,x)=(0,x),f(x,0)=f(x,0) f(0,x)=(0,x),f(x,0)=f(x,0).
(2)其余情况,后手可以选择接球,也可以选择不接球.
①后手选择接球,则他消耗 1 1 1点体力,此时轮到先手决策,转移到状态 f ( y , x − 1 ) f(y,x-1) f(y,x−1).
注意该状态的答案即 r e v ( f ( y , x − 1 ) ) rev(f(y,x-1)) rev(f(y,x−1)),其中 r e v ( a , b ) = ( b , a ) rev(a,b)=(b,a) rev(a,b)=(b,a).
②后手选择不接球,则本轮比赛结束,下一轮先手必须消耗 1 1 1点体力发球,转移到状态 f ( x , y − 1 ) + ( 0 , 1 ) f(x,y-1)+(0,1) f(x,y−1)+(0,1).
f ( x , y ) = ( x , y ) f(x,y)=(x,y) f(x,y)=(x,y).
[证] 注意到 f ( x , y ) f(x,y) f(x,y)要么等于 r e v ( f ( y , x − 1 ) ) rev(f(y,x-1)) rev(f(y,x−1)),要么等于 f ( x , y − 1 ) + ( 0 , 1 ) f(x,y-1)+(0,1) f(x,y−1)+(0,1),
下面用数学归纳法证明:
① r e v ( f ( y , x − 1 ) ) = r e v ( y , x − 1 ) = ( x − 1 , y ) rev(f(y,x-1))=rev(y,x-1)=(x-1,y) rev(f(y,x−1))=rev(y,x−1)=(x−1,y).
② f ( x , y − 1 ) + ( 0 , 1 ) = ( x , y − 1 ) + ( 0 , 1 ) = ( x , y ) f(x,y-1)+(0,1)=(x,y-1)+(0,1)=(x,y) f(x,y−1)+(0,1)=(x,y−1)+(0,1)=(x,y).
显然 ( x , y ) (x,y) (x,y)对先手来说优于 ( x − 1 , y ) (x-1,y) (x−1,y),故 f ( x , y ) = ( x , y ) f(x,y)=(x,y) f(x,y)=(x,y).
注意初始时A先发球,故 a n s = r e v ( f ( y , x − 1 ) ) = ( x − 1 , y ) ans=rev(f(y,x-1))=(x-1,y) ans=rev(f(y,x−1))=(x−1,y).
代码
void solve() {
int x, y; cin >> x >> y;
cout << x - 1 << ' ' << y << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1472D. Even-Odd Game
原题指路:https://codeforces.com/problemset/problem/1472/D
题意
给定一个长度为 n n n的整数序列 a 1 , ⋯ , a n a_1,\cdots,a_n a1,⋯,an.Alice和Bob玩游戏,Alice先手.每轮每人从序列中选一个元素并将其移除,若轮到Alice且她选的数是偶数,则将该数的值加到她的得分中;若轮到Bob且他选的数是奇数,则将该数的值加到他的得分中.两人都希望最大化自己的得分,两人都采取最优策略,最后得分高者胜,得分相等时平局.问最后谁胜或平局.
有 t ( 1 ≤ t ≤ 1 e 4 ) t\ \ (1\leq t\leq 1\mathrm{e}4) t (1≤t≤1e4)组测试数据.每组测试数据第一行输入一个整数 n ( 1 ≤ n ≤ 2 e 5 ) n\ \ (1\leq n\leq 2\mathrm{e}5) n (1≤n≤2e5).第二行输入 n n n个整数 a 1 , ⋯ , a n ( 1 ≤ a i ≤ 1 e 9 ) a_1,\cdots,a_n\ \ (1\leq a_i\leq 1\mathrm{e}9) a1,⋯,an (1≤ai≤1e9).数据保证所有测试数据的 n n n之和不超过 2 e 5 2\mathrm{e}5 2e5.
思路
设Alice的得分与Bob的得分之差为总得分 a n s ans ans,则 a n s > 0 ans>0 ans>0时Alice胜, a n s = 0 ans=0 ans=0时平局, a n s < 0 ans<0 ans<0时Bob胜.此时Alice取走偶数 x x x等价于 a n s + = x ans+=x ans+=x,Bob取走奇数 y y y等价于 a n s − = y ans-=y ans−=y.Alice想最大化 a n s ans ans,Bob想最小化 a n s ans ans.
显然两人都应贪心地选当前序列中最大的元素,即尽量让自己得分,自己得不到分也不要让对手得到太多分.
代码
void solve() {
int n; cin >> n;
vi a(n);
for (auto& ai : a) cin >> ai;
sort(rall(a));
ll ans = 0;
for (int i = 0; i < n; i++) {
if (i & 1) ans -= (a[i] % 2 == 1) * a[i];
else ans += (a[i] % 2 == 0) * a[i];
}
if (ans) cout << (ans > 0 ? "Alice" : "Bob") << endl;
else cout << "Tie" << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1480A. Yet Another String Game
原题指路:https://codeforces.com/problemset/problem/1480/A
题意 ( 2 s 2\ \mathrm{s} 2 s)
Alice和Bob玩游戏,Alice先手.初始时给定一个长度为 n n n的字符串 s = s 1 ⋯ s n s=s_1\cdots s_n s=s1⋯sn.每轮没人选一个下标 i ∈ [ 1 , n ] i\in [1,n] i∈[1,n],将 s i s_i si替换为任一非 s i s_i si的字符,所有下标都被选过时游戏结束.Alice希望结果串的字典序尽量小,Bob希望结果串的字典序尽量大,两人都采取最优策略,问结果串.
有 t ( 1 ≤ t ≤ 1000 ) t\ \ (1\leq t\leq 1000) t (1≤t≤1000)组测试数据.每组测试数据输入一个长度不超过 50 50 50且只包含小写英文字母的字符串 s s s.
思路
①对Alice操作的字符,若该字符不是’a’,则将其替换为’a’;否则替换为’b’.
②对Bob操作的字符,若该字符不是’z’,则将其替换为’z’;否则替换为’y’.
代码
void solve() {
string s; cin >> s;
for (int i = 0; i < s.length(); i++) {
if (i & 1) s[i] = s[i] == 'z' ? 'y' : 'z';
else s[i] = s[i] == 'a' ? 'b' : 'a';
}
cout << s << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
1527B1. Palindrome Game (easy version)
原题指路:https://codeforces.com/problemset/problem/1527/B1
题意
Alice和Bob玩游戏,Alice先手.初始时给定一个长度为 n n n的回文 0 − 1 0-1 0−1串 s s s.每轮每人可做如下两种操作之一:①选择一个下标 i ∈ [ 1 , n ] s . t . s [ i ] = 0 i\in[1,n]\ s.t.\ s[i]=0 i∈[1,n] s.t. s[i]=0,令 s [ i ] = 1 s[i]=1 s[i]=1,花费 1 1 1点代价;②反转整个串,花费 0 0 0点代价.操作②只能在当前的串不是回文串且上一步操作不是操作②时进行.当 s s s只包含 1 1 1时游戏结束,此时花费小者胜,两人花费相同则平局.两人都采取最优策略,问最后谁胜或平局.
有 t ( 1 ≤ t ≤ 1000 ) t\ \ (1\leq t\leq 1000) t (1≤t≤1000)组测试数据.每组测试数据第一行输入一个整数 n ( 1 ≤ n ≤ 1000 ) n\ \ (1\leq n\leq 1000) n (1≤n≤1000).第二行输入一个长度为 n n n的回文 0 − 1 0-1 0−1串 s s s.
思路
(1) s s s只包含一个 0 0 0时Bob胜.
[证] 因初始时 s s s是回文串,若 s s s只包含一个 0 0 0,则 s s s长度为奇数,且 0 0 0在中间.
因 s s s初始时是回文串,则Alice只能花费 1 1 1点代价做操作①,且操作后游戏结束.此时Alice花费比Bob多 1 1 1.
(2) s s s包含偶数个 0 0 0时Bob胜.
[证] 若Alice把 s [ i ] s[i] s[i]变为 1 1 1,则Bob把 s [ n − i + 1 ] s[n-i+1] s[n−i+1]变为 1 1 1,即保持 s s s是回文串.
此时Alice只能做操作①,当剩下最后一个 0 0 0时Bob做操作②.此时Alice花费比Bob多 1 1 1.
(3) s s s包含奇数个 0 0 0时Alice胜.
[证] 因初始时 s s s是回文串,则有一个 0 0 0在串中间,Alice第一步将其变为 0 0 0,转化为包含偶数个 0 0 0的情况.
由(2)知:包含偶数个 0 0 0时当前的后手胜,即Alice胜.
代码
void solve() {
int n; cin >> n;
int cnt = 0; // 0的个数
while (n--) {
char ch; cin >> ch;
cnt += ch == '0';
}
cout << ((cnt % 2 == 1 && cnt > 1) ? "ALICE" : "BOB") << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}