[Codeforces] games (R1600) Part.1

[Codeforces] games (R1600) Part.1

题单:https://codeforces.com/problemset?tags=games,1201-1600

74B. Train

原题指路:https://codeforces.com/problemset/problem/74/B

题意 ( 2   s 2\ \mathrm{s} 2 s)

偷渡者(Stowaway)和管理员(Controller)在火车上玩游戏.火车有编号 1 ∼ n 1\sim n 1n n n n节车厢,其中 1 1 1号车厢是头, n n n号车厢是尾.火车每分钟处于运行或停靠状态.每分钟两个玩家都会移动,且偷渡者先移动.任意时刻两玩家都知道对方的位置.

管理员有一个移动方向——朝着火车头或火车尾.每分钟他会移动到他的移动方向的下一节车厢,当他在 1 1 1号或 n n n号车厢时转向.

偷渡者的移动与火车的状态有关.若火车该分钟处于运行状态,则偷渡者可移动到相邻的一节车厢或留在所处车厢;若火车处于停靠状态且不是终点站,他会下车并从任一节车厢上车.若火车停靠若干分钟,则每分钟他都会下车再重新上车.

若某一分钟偷渡者和管理员处于同一节车厢,则管理员胜.若到终点站后偷渡者仍未负,则偷渡者胜.若偷渡者负,则希望他尽量晚负.两人都采取最优策略,问最后的胜者.若管理员胜,需他抓到偷渡者的分钟数(从 1 1 1开始).

第一行输入三个整数 n , m , k    ( 2 ≤ n ≤ 50 , 1 ≤ m , k ≤ n , m ≠ k ) n,m,k\ \ (2\leq n\leq 50,1\leq m,k\leq n,m\neq k) n,m,k  (2n50,1m,kn,m=k),分别表示火车的车厢数、偷渡者的初始位置、管理员的初始位置.第二行输入一个字符串表示管理员初始时的移动方向,其中"to head"表示他向火车头移动,"to tail"表示他向火车尾移动.数据保证他移动的方向至少还有一节车厢.第三行输入一个长度不超过 200 200 200 0 − 1 0-1 01串表示每分钟火车的状态,其中 0 0 0表示火车处于运行状态, 1 1 1表示火车处于停靠状态.

思路

偷渡者的最优策略:①在火车运行时与管理员同向移动;②在火车停靠时在与管理员移动方向相反的最远的车厢上车.

模拟该过程即可.

代码

void solve() {
  int n, m, k; cin >> n >> m >> k;  // m表示偷渡者的位置,k表示管理员的位置
  int face = 0;  // 管理者的移动方向,0表示向火车尾,1表示向火车头
  string s; cin >> s >> s;
  if (s[0] == 'h') face = 1;
  cin >> s;
  s = " " + s;

  for (int i = 1; s[i]; i++) {
    if (s[i] == '0') {  // 火车处于运行状态
      if (face) {  // 管理员向火车头走
        m = max(1, m - 1);  // 若偷渡者在1号车厢,则他留在原地比走到2号车厢更优
        k--;
        if (m == k) {
          cout << "Controller " << i;
          return;
        }
        if (k == 1) face = 0;  // 管理员转向
      }
      else {  // 管理员向火车尾走
        m = min(n, m + 1);  // 若偷渡者在n号车厢,则他留在原地比走到(n-1)号车厢更优
        k++;
        if (m == k) {
          cout << "Controller " << i;
          return;
        }
        if (k == n) face = 1;  // 管理员转向
      }
    }
    else {  // 火车处于停靠状态
      if (face) {  // 管理员向火车头走
        if (--k == 1) face = 0;  // 管理员转向
        m = n;  // 偷渡者在与管理员移动方向相反的最远的车厢上车
      }
      else {
        if (++k == n) face = 1;  // 管理员转向
        m = 1;  // 偷渡者在与管理员移动方向相反的最远的车厢上车
      }
    }
  }
  cout << "Stowaway";
}

int main() {
  solve();
}


120E. Put Knight!

原题指路:https://codeforces.com/problemset/problem/120/E

题意

在这里插入图片描述

一个位于红色格子的骑士能攻击到所有蓝色格子.A和B轮流在在一个 n × n n\times n n×n棋盘上放置一个骑士,使得任意两骑士间不能互相攻击,A先手.两人都采取最优策略,若最后A胜,输出 0 0 0;否则输出 1 1 1.

t    ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t  (1t100)组测试数据.每组测试数据输入一个整数 n    ( 1 ≤ n ≤ 1 e 4 ) n\ \ (1\leq n\leq 1\mathrm{e}4) n  (1n1e4).

思路

最优策略:先手占中心位置,然后先手放置在后手放置的位置关于中心对称的位置.

n n n为奇数时,先手能占中心位置,先手必胜.

n n n为偶数时,不存在中心位置,后手必胜.

代码

void solve() {
  int n; cin >> n;
  cout << (!(n & 1)) << endl;
}

int main() {
  CaseT  // 单测时注释掉该行
    solve();
}


150A. Win or Freeze

原题指路:https://codeforces.com/problemset/problem/150/A

题意 ( 2   s 2\ \mathrm{s} 2 s)

A和B两人玩游戏,A先手.初始时纸上有一个整数 n n n,每轮每人写出一个上一个写的数的非平凡因子(非 1 1 1和它本身的因子),不能操作者胜.给定 n    ( 1 ≤ n ≤ 1 e 13 ) n\ \ (1\leq n\leq 1\mathrm{e}13) n  (1n1e13),问最后谁胜利.若A胜,第一行输出 1 1 1,第二行输出他的第一步操作,若他无法进行第一次操作,输出 0 0 0;若B胜,输出 2 2 2.

思路

只有当 n n n形如 p q pq pq p 2 p^2 p2时B胜,其中 p , q p,q p,q为素因子.

对其余情况,先预处理出 n n n的素因子后,若素因子个数为 1 1 1(含重复的素因子),则 n n n为素数,进而A无法进行第一次操作,输出 1 1 1;否则A至少有两个素因子,输出前两个素因子之积即可.

代码

void solve() {
	ll n; cin >> n;
    
  if (n == 1) {
    cout << 1 << endl << 0;
    return;
  }

  vl divisors;
  for (ll i = 2; i <= sqrt(n); i++) {
    if (n % i == 0) {
      while (n % i == 0) {
        n /= i;
        divisors.push_back(i);
      }
    }
  }
  if(n > 1) divisors.push_back(n);

  if (divisors.size() == 2) cout << 2;
  else {
    cout << 1 << endl;
    cout << (divisors.size() == 1 ? 0 : divisors[0] * divisors[1]);
  }
}

int main() {
	solve();
}


197A. Plate Game

原题指路:https://codeforces.com/problemset/problem/197/A

题意 ( 2   s 2\ \mathrm{s} 2 s)

A和B轮流在一个 a × b a\times b a×b的矩形桌子上放置半径为 r r r的圆盘,A先手,要求圆盘间不能重叠,圆盘不能超出桌子区域,无法放置者负.两人都采取最优策略,问谁胜.

第一行输入三个整数 a , b , r    ( 1 ≤ a , b , r ≤ 100 ) a,b,r\ \ (1\leq a,b,r\leq 100) a,b,r  (1a,b,r100).

思路

最优策略:先手先在桌子中心放圆盘,随后放在与后手中心对称的位置.

故先手负当且仅当第一步无法放置圆盘.

代码

void solve() {
  int a, b, r; cin >> a >> b >> r;
  cout << (a >= 2 * r && b >= 2 * r ? "First" : "Second");
}

int main() {
  solve();
}


257B. Playing Cubes

原题指路:https://codeforces.com/problemset/problem/257/B

题意 ( 2   s 2\ \mathrm{s} 2 s)

n n n个红方块和 m    ( 1 ≤ n , m ≤ 1 e 5 ) m\ \ (1\leq n,m\leq 1\mathrm{e}5) m  (1n,m1e5)个蓝方块.A和B轮流将方块排成一条线,A先手.每轮每人选一个剩下的方块,接在已经排好的线最后.所有方块排完后,A的得分是相邻两个方块颜色相同的对数,B的得分是相邻两个方块颜色不同的对数.两人都想最大化自己的得分并都采取最优策略,问他们两人最后的得分.

思路

最优策略:A每次放置与上一个位置同色的方块,B每次放置与上一个位置异色的方块.

①对A,前 2 min ⁡ { n , m } 2\min\{n,m\} 2min{n,m}轮中只有A自己放置的操作才能得分.

​ 之后的 ( n + m − 2 min ⁡ { n , m } ) (n+m-2\min\{n,m\}) (n+m2min{n,m})轮只剩下一种颜色,不管谁放置都是A得分.

​ 故A得分 min ⁡ { n , m } + ( n + m − 2 min ⁡ { n , m } ) − 1 = max ⁡ { n , m } − 1 \min\{n,m\}+(n+m-2\min\{n,m\})-1=\max\{n,m\}-1 min{n,m}+(n+m2min{n,m})1=max{n,m}1,其中 − 1 -1 1是因为A第一轮不得分.

②对B,因两人得分之和为 ( n + m − 1 ) (n+m-1) (n+m1),故B的得分为 min ⁡ { n , m } \min\{n,m\} min{n,m}.

n n n个红方块和 m m m个蓝方块的排列中至多有 min ⁡ { n , m } \min\{n,m\} min{n,m}对相邻相异的颜色,

​ 该最大值可以达到,只需每次都放上一个位置异色的方块即可.

代码

void solve() {
  int n, m; cin >> n >> m;
  cout << max(n, m) - 1 << ' ' << min(n, m);
}

int main() {
  solve();
}


276B. Little Girl and Game

原题指路:https://codeforces.com/problemset/problem/276/B

题意 ( 2   s ) (2\ \mathrm{s}) (2 s)

First和Second玩游戏,First先手.初始时给定一个只包含小写英文字母的字符串 s    ( 1 ≤ ∣ s ∣ ≤ 1000 ) s\ \ (1\leq |s|\leq 1000) s  (1s1000).每轮每人有操作:移除 s s s中的任一个字符.若玩家在操作前可通过重排 s s s使其变为一个回文串,则他获胜.两人都采取最优策略,问最后谁获胜.

思路

可重排 s s s使其变为一个回文串的充要条件是:至多有一个出现次数为奇数的字符.

显然Second胜当且仅当初始时 s s s有偶数个出现次数为奇数的字符.

代码

void solve() {
  string s; cin >> s;
  map<char, int> cnt;  // 每个字符出现的次数
  for (auto ch : s) cnt[ch]++;

  int odd = 0;  // 出现次数为奇数的字符的个数
  for (auto [u, v] : cnt) odd += v & 1;

  cout << ((odd && odd % 2 == 0) ? "Second" : "First");
}

int main() {
  solve();
}


293A. Weird Game

原题指路:https://codeforces.com/problemset/problem/293/A

题意 ( 2   s ) (2\ \mathrm{s}) (2 s)

A和B玩游戏,A先手.初始时A有一个长度为 2 n 2n 2n 0 − 1 0-1 01 s = s 1 ⋯ s 2 n s=s_1\cdots s_{2n} s=s1s2n,B有一个长度为 2 n 2n 2n 0 − 1 0-1 01 t = t 1 ⋯ t 2 n t=t_1\cdots t_{2n} t=t1t2n.每人每轮选择一个未被禁止的下标 i ∈ [ 1 , n ] i\in[1,n] i[1,n],将自己的串中下标 i i i的字符写在自己的纸上,并禁止下标 i i i.两人都无法操作时游戏结束,此时两人重排自己纸上写的数字分别得到一个二进制数,数较大者获胜,若二进制数相等则平局.问最后谁胜.

第一行输入一个整数 n    ( 1 ≤ n ≤ 1 e 6 ) n\ \ (1\leq n\leq 1\mathrm{e}6) n  (1n1e6).第二行输入一个长度为 2 n 2n 2n 0 − 1 0-1 01 s s s.第三行输入一个长度为 2 n 2n 2n 0 − 1 0-1 01 t t t.

思路

显然获得尽量多的 1 1 1的人胜,故最优策略是贪心地选未被禁止的 1 1 1,若无未被禁止的 1 1 1可选,则选对手的串有 1 1 1的位置.模拟该过程即可.

代码

void solve() {
  int n; string s, t; cin >> n >> s >> t;
  n <<= 1;

  int ans1 = 0, ans2 = 0;  // A和B拿到的1的个数
  int cnt = 0;  // s[i] = t[i] = 1的下标i的个数
  for (int i = 0; i < n; i++) {
    if (s[i] == '1' && t[i] == '1') cnt++;
    else if (s[i] == '1' && t[i] == '0') ans1++;
    else if (s[i] == '0' && t[i] == '1') ans2++;
  }
  if (cnt & 1) ans2--;  // B少拿一个s[i] = t[i] = 1的下标

  if (ans1 > ans2) cout << "First";
  else cout << (ans2 > ans1 + 1 ? "Second" : "Draw");
}

int main() {
  solve();
}


346A. Alice and Bob

原题指路:https://codeforces.com/problemset/problem/346/A

题意 ( 2   s ) (2\ \mathrm{s}) (2 s)

Alice和Bob两人玩游戏,Alice先手.初始时给定一个整数集合 S S S.每轮玩家选两个相异的整数 x , y ∈ S x,y\in S x,yS,使得 ∣ x − y ∣ ∉ S |x-y|\not\in S xyS,并将 ∣ x − y ∣ |x-y| xy加入 S S S中,不能操作者负.问最后谁赢.

第一行输入一个整数 n    ( 2 ≤ n ≤ 100 ) n\ \ (2\leq n\leq 100) n  (2n100).第二行输入 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).

思路

类似于闭包,无论中间过程,最后得到的集合都相同.设 g = gcd ⁡ 1 ≤ i ≤ n a i \displaystyle g=\gcd_{1\leq i\leq n}a_i g=1ingcdai,则最终集合为 { d , 2 d , 3 d , ⋯   , max ⁡ { x i } } \{d,2d,3d,\cdots,\max\{x_i\}\} {d,2d,3d,,max{xi}},故轮数为 max ⁡ { x i } d \dfrac{\max\{x_i\}}{d} dmax{xi},判断其奇偶性即可.

代码

void solve() {
	int n; cin >> n;
	valarray<int> a(n);
	int g = 0;  // gcd
	for (auto& ai : a) {
		cin >> ai;
		g = gcd(g, ai);
	}

	int ans = a.max() / g - n;
	cout << (ans & 1 ? "Alice" : "Bob");
}

int main() {
	solve();
}


546C. Soldier and Cards

原题指路:https://codeforces.com/problemset/problem/546/C

题意 ( 2   s ) (2\ \mathrm{s}) (2 s)

n n n张牌,分别写着 1 ∼ n 1\sim n 1n n n n个整数.A和B玩游戏,A先手.初始时将 n n n张牌以某种方式分配给A和B,每人拿到一叠牌.每轮每人从自己的牌堆中拿出顶上的牌比大小,点数较大者拿走对手的牌和自己的牌,先将对手的牌放在牌堆顶部,再将自己的牌放在牌堆顶部.手中无牌者负.若游戏能一直进行下去,输出 − 1 -1 1;否则先输出游戏轮数,再输出胜者(A为 1 1 1,B为 2 2 2).

第一行输入一个整数 n    ( 2 ≤ n ≤ 10 ) n\ \ (2\leq n\leq 10) n  (2n10).第二行先输入一个整数 k 1    ( 1 ≤ k 1 ≤ n − 1 ) k_1\ \ (1\leq k_1\leq n-1) k1  (1k1n1),表示A手中的牌数.接下来输入 k 1 k_1 k1个范围为 [ 1 , n ] [1,n] [1,n]的整数,从左往右依次表示A的牌堆从上到下的牌.第三行先输入一个整数 k 2    ( k 1 + k 2 = n ) k_2\ \ (k_1+k_2=n) k2  (k1+k2=n),表示B手中的牌数.接下来输入 k 2 k_2 k2个范围为 [ 1 , n ] [1,n] [1,n]的整数,从左往右依次表示B的牌堆从上到下的牌.数据保证所有牌相异.

思路

n n n张牌有 n ! n! n!种排列,在 n n n张牌的任一排列的间隙中插隔板,左边为A的牌,右边为B的牌,有 ( n − 1 ) (n-1) (n1)种方案,故总方案数为 n ! ⋅ ( n − 1 ) n!\cdot (n-1) n!(n1). n = 10 n=10 n=10时,方案数为 M A X _ R O U N D = 32659200 MAX\_ROUND=32659200 MAX_ROUND=32659200.模拟游戏过程,若轮数超过 M A X _ R O U N D MAX\_ROUND MAX_ROUND则游戏状态出现环,可一直进行下去.

代码

const int MAX_ROUND = 32659200;

void solve() {
  int n; cin >> n;
  qi que1, que2;
  int k; cin >> k;
  while (k--) {
    int x; cin >> x;
    que1.push(x);
  }
  cin >> k;
  while (k--) {
    int x; cin >> x;
    que2.push(x);
  }

  int round;
  for (round = 0; round <= MAX_ROUND && que1.size () && que2.size(); round++) {
    int a = que1.front(); que1.pop();
    int b = que2.front(); que2.pop();
    if (a > b) que1.push(b), que1.push(a);
    else que2.push(a), que2.push(b);
  }

  if (que1.size() && que2.size()) cout << -1;
  else if (que1.size()) cout << round << " 1";
  else cout << round << " 2";
}

int main() {
  solve();
}


570B. Simple Game

原题指路:https://codeforces.com/problemset/problem/570/B

题意

给定两个整数 n , m    ( 1 ≤ n , m ≤ 1 e 9 ) n,m\ \ (1\leq n,m\leq 1\mathrm{e}9) n,m  (1n,m1e9).选一个整数 a ∈ [ 1 , n ]   s . t .   ∣ c − a ∣ < ∣ c − m ∣ a\in[1,n]\ s.t.\ |c-a|<|c-m| a[1,n] s.t. ca<cm的概率最大,其中 c c c等概率地取 1 ∼ n 1\sim n 1n内的整数.

思路

∣ c − a ∣ < ∣ c − m ∣ |c-a|<|c-m| ca<cm即随机出的 c c c a a a比距 m m m近.

最优策略取 a = m ± 1 a=m\pm 1 a=m±1,否则 a a a m m m间的整数中离 m m m更近的数更多,这是不优的.

a = m − 1 a=m-1 a=m1时,符合条件的 c ∈ [ 1 , m − 1 ] c\in [1,m-1] c[1,m1],有 ( m − 1 ) (m-1) (m1)个.

a = m + 1 a=m+1 a=m+1时,符合条件的 c ∈ [ m + 1 , n ] c\in[m+1,n] c[m+1,n],有 ( n − m ) (n-m) (nm)个.

n − m > m − 1 n-m>m-1 nm>m1,即 n > 2 m − 1 n>2m-1 n>2m1,亦即 n ≥ 2 m n\geq 2m n2m时,取 a = m + 1 a=m+1 a=m+1;否则取 a = m − 1 a=m-1 a=m1.

注意 a = m − 1 a=m-1 a=m1 m = 1 m=1 m=1 a = 0 ∉ [ 1 , n ] a=0\notin[1,n] a=0/[1,n],故需特判 n = m = 1 n=m=1 n=m=1的情况或 ( m − 1 ) (m-1) (m1) 1 1 1 max ⁡ \max max.

代码

void solve() {
  int n, m; cin >> n >> m;
  if (n == 1 && m == 1) cout << 1;
  else cout << (n >= 2 * m ? m + 1 : m - 1);
}

int main() {
  solve();
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值