[Codeforces] games (R1200) Part.2

[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 1n n n n张卡,每张卡有一个权值,卡的权值两两相异.A和B玩游戏,A先手.初始时所有的卡分配到A和B手中.每轮每人从手中的卡选一张倒扣在桌面上(对手看不见),两人都放完后揭晓卡,卡权值较大的人将两张卡都拿走.手中无卡者负.现给定初始时A和B手中的卡,两人都采取最优策略,若A必胜则输出"YES";否则输出"NO".

t    ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t  (1t100)组测试数据.每组测试数据第一行输入三个整数 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  (2n100,1k1n1,1k2n1,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  (1ain),表示初始时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  (1bin),表示初始时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 01矩阵,其中 0 0 0表示该格子未被染色, 1 1 1表示该格子被染色.Ashish和Vivek轮流给矩阵染色Ashish先手.染色要求要染色的格子与已染色的格子不在同一行和同一列.两人都采取最优策略,问最后谁胜.

t    ( 1 ≤ t ≤ 50 ) t\ \ (1\leq t\leq 50) t  (1t50)组测试数据.每组测试数据第一行输入两个整数 n , m    ( 1 ≤ n , m ≤ 50 ) n,m\ \ (1\leq n,m\leq 50) n,m  (1n,m50).第二行输入一个 n × m n\times m n×m 0 − 1 0-1 01矩阵.

思路

设未被染色的行数为 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 01 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 1n 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  (1t1000)组测试数据.每组测试数据第一行输入一个整数 n    ( 1 ≤ n ≤ 1 e 5 ) n\ \ (1\leq n\leq 1\mathrm{e}5) n  (1n1e5).第二行输入 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  (1ai1e9).数据保证所有测试数据的 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 01 s s s.Alice和Bob轮流操作,Alice先手.每轮每人选择一段非空的连续相同的字符,将它们删去,当 s s s为空时游戏结束.每人的得分为他删去的 1 1 1的个数.若两人都想最大化自己的得分,求Alice的最大得分.

t    ( 1 ≤ t ≤ 500 ) t\ \ (1\leq t\leq 500) t  (1t500)组测试数据.每组测试数据输入一个 0 − 1 0-1 01 s    ( 1 ≤ ∣ s ∣ ≤ 100 ) s\ \ (1\leq |s|\leq 100) s  (1s100).

思路

最优策略:每人每轮选当前最长的连续 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 1n.每轮每人选一个当前未被标记的位置将其标记,轮到A时,他只能选择奇数下标的位置;轮到B时,他只能选择偶数下标的位置.当只剩下一个未被标记的位置时游戏结束,此时若剩下的数字为奇数,则A胜;否则B胜.两人都采取最优策略,若最后A胜,输出 1 1 1;否则输出 2 2 2.

t    ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t  (1t100)组测试数据.每组测试数据第一行输入一个整数 n    ( 1 ≤ n ≤ 1000 ) n\ \ (1\leq n\leq 1000) n  (1n1000).第二行输入一个 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  (1t1e4)组测试数据.每组测试数据输入两个整数 x , y    ( 1 ≤ x , y ≤ 1 e 6 ) x,y\ \ (1\leq x,y\leq 1\mathrm{e}6) x,y  (1x,y1e6).

思路

设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,x1).

​ 注意该状态的答案即 r e v ( f ( y , x − 1 ) ) rev(f(y,x-1)) rev(f(y,x1)),其中 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,y1)+(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,x1)),要么等于 f ( x , y − 1 ) + ( 0 , 1 ) f(x,y-1)+(0,1) f(x,y1)+(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,x1))=rev(y,x1)=(x1,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,y1)+(0,1)=(x,y1)+(0,1)=(x,y).

显然 ( x , y ) (x,y) (x,y)对先手来说优于 ( x − 1 , y ) (x-1,y) (x1,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,x1))=(x1,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  (1t1e4)组测试数据.每组测试数据第一行输入一个整数 n    ( 1 ≤ n ≤ 2 e 5 ) n\ \ (1\leq n\leq 2\mathrm{e}5) n  (1n2e5).第二行输入 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  (1ai1e9).数据保证所有测试数据的 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=s1sn.每轮没人选一个下标 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  (1t1000)组测试数据.每组测试数据输入一个长度不超过 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 01 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  (1t1000)组测试数据.每组测试数据第一行输入一个整数 n    ( 1 ≤ n ≤ 1000 ) n\ \ (1\leq n\leq 1000) n  (1n1000).第二行输入一个长度为 n n n的回文 0 − 1 0-1 01 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[ni+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();
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值