AtCoder Beginner Contest 349 A~F

2024-04-15 01:36
文章标签 atcoder beginner contest 349

本文主要是介绍AtCoder Beginner Contest 349 A~F,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

A. Zero Sum Game(思维)

题意

N N N个人一起参加游戏,开始时每个人均拥有 0 0 0点分数。每轮游戏只会在两个人之间进行,胜者将得到 1 1 1分,败者将失去 1 1 1分。已知结束游戏后前 N − 1 N - 1 N1个人的分数 A 1 , A 2 , … , A N − 1 A_1, A_2, \ldots, A_{N - 1} A1,A2,,AN1,问,最后一个人的分数是多少?

分析

既然每轮游戏将会产生两个分数 1 1 1 − 1 -1 1,那么对于 N N N个人来说,总分总是固定为 0 0 0的,因此想要知道 A N A_N AN,可以使用总分减去每个人的分数,即 A N = 0 − ∑ i = 1 N − 1 A i A_N = 0 - \sum\limits_{i = 1}^{N - 1}A_i AN=0i=1N1Ai

代码

#include<bits/stdc++.h>
using namespace std;void solve() {int n;cin >> n;int sum = 0;for (int i = 2; i <= n; i++) {int a;cin >> a;sum += a;}cout << -sum << endl;
}int main() {solve();return 0;
}

B. Commencement(桶数组)

题意

给出一个仅包含小写字母的字符串 S S S,定义一个字符串是一个好字符串需要对于每一个大于等于 1 1 1 i i i均满足以下要求:

  • 出现次数为 i i i次的字母只可以有 0 0 0个或 2 2 2个。

问:给出的字符串是否为好字符串?

分析

可以使用 c n t cnt cnt数组记录每个字母的出现次数,然后再使用桶数组或 m a p map map记录每个出现次数的字母个数。

最后检查一遍,是否每个出现次数 i i i对应的字母个数,如果均为 0 0 0个或 2 2 2个,那么就输出Yes,否则,输出No

代码

#include<bits/stdc++.h>
using namespace std;int cnt[130];
vector<int> V[105];void solve() {string s;cin >> s;for (auto i : s) {cnt[i - 'a']++;}for (int i = 0; i <= 25; i++) {if (cnt[i]) {V[cnt[i]].push_back(i);}}int n = s.size();for (int i = 1; i <= n; i++) {if (V[i].size() != 0 && V[i].size() != 2) {cout << "No" << endl;return;}}cout << "Yes" << endl;
}int main() {solve();return 0;
}

C.Airport Code(思维)

题意

Airport Code:如果从字符串 S S S中按以下两种方法获得一个新的字符串,那么这个新获得的字符串就叫做Airport Code

    1. 从字符串 S S S中取出一个长为 3 3 3的子序列,并把这个子序列中所有字母变成大写字母。
    1. 从字符串 S S S中取出一个长为 2 2 2的子序列,并把这个子序列中所有字母变成大写字母,然后在这个子序列后加上一个大写字母 X X X

给出两个字符串 S S S T T T,问字符串 T T T是不是字符串 S S SAirport Code

分析

对两个字符串进行字符串匹配(注意大小写),然后根据匹配上的数量进行判断:

    1. 三个字母都匹配上了,必然成立
    1. 匹配上前两个字母,且最后一个未被匹配的字母为 X X X,也成立
    1. 其他情况均不成立

代码

#include<bits/stdc++.h>
using namespace std;void solve() {string s, t;cin >> s >> t;int len_t = t.size();int maxn = 2;if (t[2] == 'X') maxn--;int j = 0;for (auto i : s) {if (j <= maxn && i - 32 == t[j]) {j++;}}if (j > maxn) cout << "Yes" << endl;else cout << "No" << endl;
}int main() {solve();return 0;
}

D.Divide Interval(贪心)

题意

对于两个非负整数 l , r ( l < r ) l, r(l < r) l,r(l<r),定义序列 S ( l , r ) = l , l + 1 , … , r − 1 S(l, r) = l, l + 1, \ldots, r - 1 S(l,r)=l,l+1,,r1。而一个序列为好的序列需要满足 S ( l , r ) S(l, r) S(l,r)中的 l = 2 i j , r = 2 i ( j + 1 ) l = 2^{i}j, r = 2^{i}(j + 1) l=2ij,r=2i(j+1)

给出两个非负整数 L , R ( L < R ) L, R(L < R) L,R(L<R),问,最少使用多少个好的序列 S ( l i , r i ) S(l_i, r_i) S(li,ri),才能组成 L ∼ R − 1 L \sim R - 1 LR1之间的所有数字。

分析

由于好的序列的 l = 2 i j , r − l = 2 i l = 2^{i}j, r - l = 2^{i} l=2ij,rl=2i,那么为了序列数量尽可能少,取的 2 i 2^{i} 2i就要尽可能大,而 l = 2 i j l = 2^{i}j l=2ij,则 l l l必须为 2 i 2^{i} 2i的倍数,因此,可以对 i i i从大到小进行枚举,当 l l l 2 i 2^{i} 2i倍数时,就可以继续检查 l + 2 i l + 2^{i} l+2i后是否会超过右边界 R R R,如果也没有超过右边界,那么就表示当前序列能当前能选的所有序列中最长的一个,将当前序列的起点 l l l和终点 l + 2 i l + 2^{i} l+2i记录到vector中,并将起点修改为 l + 2 i l + 2^{i} l+2i继续寻找下一个序列。

Tips

  1. 2 i 2^{i} 2i可以通过位运算 1 < < i 1 << i 1<<i快速得到
  2. 由于本题数据范围较大 R ≤ 2 60 R \le 2^{60} R260,而C++程序中写下的数字 1 1 1默认是int类型,那么直接使用 1 < < i 1 << i 1<<i会因为数据溢出导致程序出现错误,需要使用 1 l l 1ll 1ll代替数字 1 1 1,写作 1 l l < < i 1ll << i 1ll<<i

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;vector<pair<ll, ll>  > ans;void solve() {ll l, r;cin >> l >> r;while (l < r) {for (ll i = 60; i >= 0; i--) {if (l % (1ll << i) == 0 && (l / (1ll << i) + 1) * (1ll << i) <= r) {ans.push_back({l, (l / (1ll << i) + 1) * (1ll << i)});l = (l / (1ll << i) + 1) * (1ll << i);break;}}}cout << ans.size() << endl;for (auto i : ans) {cout << i.first << ' ' << i.second << endl;}
}int main() {solve();return 0;
}

E.Weighted Tic-Tac-Toe(博弈)

题意

给出一个 3 × 3 3 \times 3 3×3的网格,每个网格中包含着一个数字,其中第 i i i行第 j j j列的数字为 A i , j A_{i, j} Ai,j,保证 ∑ i = 1 3 ∑ j = 1 3 A i , j \sum\limits_{i = 1}^{3}\sum\limits_{j = 1}^{3}A_{i, j} i=13j=13Ai,j是个奇数。

开始时,网格上每个位置上均为空着的的,高桥和Aoki将在这个网格上玩井字棋。

如果谁赢下了这场井字棋,谁就是胜者。

如果出现平局,则看两名选手放置棋子的方格数字之和,谁的数字之和更大,那么谁就赢下了这局游戏。

高桥为先手,假设两人均采取最优策略,问谁将会赢下这场游戏。

分析

考虑贪心,发现局部最优解无法推出全局最优解,当前最优的策略可能会将自己推入必败点,因此不能使用贪心思维来解决本题。

考虑进行博弈,使用dfs枚举操作,看两名选手操作后能否将对手推入必败点,如果可以,那么当前状态就是必胜点,而如果没有任何办法使对手进入必败点,那么说明自己当前状态已经是必败点了。

使用 d f s ( i ) dfs(i) dfs(i)表示 i i i操作后的胜负情况, d f s ( i ) = 1 dfs(i) = 1 dfs(i)=1表示先手获胜, d f s ( i ) = 0 dfs(i) = 0 dfs(i)=0表示后手获胜。

每轮搜索时,由于都可能出现已经决出胜负的情况,因此,在搜索开头就需要检查胜负情况,当出现以下情况时,说明已经决出胜负了:

    1. 某一行某一列某一对角线已经出现放置了连续的三个同色棋子
    1. 网格中已经被棋子放满了

对于情况1,根据放置的棋子颜色返回本局游戏的结果

对于情况2,检查比赛双方的数字之和,数字之和较大的选手获胜

而如果情况1,2均为出现,则继续搜索并放置棋子。

hint

  • 本题数据范围较大,需要使用long long类型存储数据

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;ll a[5][5], vis[5][5], score[5];int check() {for (int i = 1; i <= 3; i++) {if (vis[i][1] != 0 && vis[i][1] == vis[i][2] && vis[i][2] == vis[i][3]) return vis[i][1];if (vis[1][i] != 0 && vis[1][i] == vis[2][i] && vis[2][i] == vis[3][i]) return vis[1][i];}if (vis[1][1] != 0 && vis[1][1] == vis[2][2] && vis[2][2] == vis[3][3]) return vis[1][1];if (vis[1][3] != 0 && vis[1][3] == vis[2][2] && vis[2][2] == vis[3][1]) return vis[1][3];for (int i = 1; i <= 3; i++) {for (int j = 1; j <= 3; j++) {if (vis[i][j] == 0) return 0;}}return 3;
}int dfs(int op) {int ans = check();if (ans == 3) return score[1] > score[2];//平局,由分数else if (ans != 0) return ans % 2;for (int i = 1; i <= 3; i++) {for (int j = 1; j <= 3; j++) {if (vis[i][j] == 0) {score[op] += a[i][j];vis[i][j] = op;int res = dfs(op == 1 ? 2 : 1);score[op] -= a[i][j];vis[i][j] = 0;if (op % 2 == res) {//返回的结果也需根据当前选手来进行判断return res;}}}}return op == 1 ? 0 : 1;//op为1,则表示先手没有必胜策略,先手必败//反之,后手必败
}void solve() {for (int i = 1; i <= 3; i++) {for (int j = 1; j <= 3; j++) {cin >> a[i][j];}}int ans = dfs(1);if (ans == 1) cout << "Takahashi" << endl;else cout << "Aoki" << endl;
}int main() {solve();return 0;
}

F.Subsequence LCM(DP)

题意

给出一个包含 N N N个数字的数组 A = A 1 , A 2 , … , A N A = A_1, A_2, \ldots, A_N A=A1,A2,,AN,以及一个正整数 M M M,问,在数组 A A A中有多少个子序列中,所有数字的最小公倍数恰好为 M M M

分析

由唯一分解定理可知,任何一个合数均可被分解成若干个素数的幂次相乘的形式,而 M ≤ 1 0 16 M \le 10^{16} M1016,而前14个素数的乘积约等于 1.3 e 16 > 1 0 16 1.3e16 > 10^{16} 1.3e16>1016,因此, M M M最多只可能被分成 13 13 13个素数乘积的形式。

然后考虑哪些因素会影响到最小公倍数,不难想到,对于 M = p 1 x 1 × p 2 x 2 … M = p_1^{x_{1}} \times p_2^{x_{2}} \ldots M=p1x1×p2x2,每个 p i x j p_{i}^{x_{j}} pixj,均取自包含子数组中包含 p i p_{i} pi这个因子的最高次项,那么,如果想要组成数字 M M M,就需要保证子数字对于 p i x j p_{i}^{x_{j}} pixj,均能至少取出其中一个数字包含该因子,同时该数字包含素因子 p i p_{i} pi的次数不能超过 x j x_{j} xj

因此,可以将输入的数字转化为仅保留该数字包含数字 M M M p i x j p_{i}^{x_{j}} pixj这些因子的形式,即如果包含因子 p i p_i pi,但次数低于 x j x_{j} xj,就将该因子去掉,因为该因子不会对最小公倍数产生贡献,然后将剩余的数字存储到数组中,即使用 c n t [ i ] cnt[i] cnt[i]表示对答案产生 i i i贡献的数字个数。

如果包含了其他因子,或因子次数过高,那么必然不能属于答案的一部分,可以将该数字直接舍去。

然后考虑初始方案,不难想到,对于 c n t [ 0 ] cnt[0] cnt[0],这些数字不会对答案产生贡献,但也不会影响到答案,因此,任取这些数字均能产生一种不同的答案,那么这些数字对于每组方案均能产生 2 c n t [ 0 ] 2^{cnt[0]} 2cnt[0]的贡献。

使用二进制枚举对组成数字 M M M的素因子进行枚举,并使用背包算法记录方案数量(当二进制枚举枚举到的数字有 n u m num num个,不难想到,只要结果中包含至少一个该数字,就能保证结果包含这些数字对应的因子,那么取这些数字的方案总数为 2 n u m − 1 2^{num} - 1 2num1,减去的1为全部数字均不取的方案数)。

M M M的素因子有 T T T种,那么最后的答案即为 d p [ ( 1 < < T ) − 1 ] dp[(1 << T) - 1] dp[(1<<T)1],其中 ( 1 < < T ) − 1 (1 << T) - 1 (1<<T)1为长度为 T T T的全 1 1 1二进制串,表示包含了 M M M的所有的素因子。

坑点

M = 1 M = 1 M=1时,会多计算一个答案,需要将答案减去。

代码

#include <bits/stdc++.h>using namespace std;
typedef long long ll;ll n, m, a[200005], mod = 998244353;
ll p[20], fact[20], pw[200005], cnt[200005], dp[200005];int main() {cin >> n >> m;int id = 0;ll num = m;for (ll i = 2; i * i <= num; i++) {if (num % i == 0) {p[id] = i;fact[id] = 1;while (num % i == 0) {fact[id] *= i;num /= i;}id++;}}if (num != 1) {p[id] = num;fact[id++] = num;}for (int i = 1; i <= n; i++) {cin >> a[i];ll val = 0;//记录a[i]对答案的贡献for (int j = 0; j < id; j++) {if (a[i] % fact[j] == 0) {a[i] /= fact[j];if (a[i] % p[j] == 0) break;val |= (1 << j);}while (a[i] % p[j] == 0) {a[i] /= p[j];}}if (a[i] == 1) {cnt[val]++;}}pw[0] = 1;for (int i = 1; i <= n; i++) {pw[i] = pw[i - 1] * 2 % mod;}dp[0] = pw[cnt[0]];for (int i = 1; i < (1 << id); i++) {for (int j = (1 << id) - 1; j >= 0; j--) {dp[i | j] = (dp[i | j] + dp[j] * (pw[cnt[i]] - 1)) % mod;}}if (!id) dp[(1 << id) - 1]--;cout << dp[(1 << id) - 1] << endl;return 0;
}

赛后交流

在比赛结束后,会在交流群中给出比赛题解,同学们可以在赛后查看题解进行补题。

群号: 704572101,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。

这篇关于AtCoder Beginner Contest 349 A~F的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/904569

相关文章

2014 Multi-University Training Contest 8小记

1002 计算几何 最大的速度才可能拥有无限的面积。 最大的速度的点 求凸包, 凸包上的点( 注意不是端点 ) 才拥有无限的面积 注意 :  凸包上如果有重点则不满足。 另外最大的速度为0也不行的。 int cmp(double x){if(fabs(x) < 1e-8) return 0 ;if(x > 0) return 1 ;return -1 ;}struct poin

2014 Multi-University Training Contest 7小记

1003   数学 , 先暴力再解方程。 在b进制下是个2 , 3 位数的 大概是10000进制以上 。这部分解方程 2-10000 直接暴力 typedef long long LL ;LL n ;int ok(int b){LL m = n ;int c ;while(m){c = m % b ;if(c == 3 || c == 4 || c == 5 ||

2014 Multi-University Training Contest 6小记

1003  贪心 对于111...10....000 这样的序列,  a 为1的个数,b为0的个数,易得当 x= a / (a + b) 时 f最小。 讲串分成若干段  1..10..0   ,  1..10..0 ,  要满足x非递减 。  对于 xi > xi+1  这样的合并 即可。 const int maxn = 100008 ;struct Node{int

AtCoder Beginner Contest 370 Solution

A void solve() {int a, b;qr(a, b);if(a + b != 1) cout << "Invalid\n";else Yes(a);} B 模拟 void solve() {qr(n);int x = 1;FOR(i, n) FOR(j, i) qr(a[i][j]);FOR(i, n) x = x >= i ? a[x][i]: a[i][x];pr2(

CF Bayan 2015 Contest Warm Up B.(dfs+暴力)

B. Strongly Connected City time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/475/probl

CF Bayan 2015 Contest Warm Up A.(模拟+预处理)

A. Bayan Bus time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/475/problem/A The fi

AtCoder Beginner Contest 369 D - Bonus EXP 动态规划

原题链接: https://atcoder.jp/contests/abc369/tasks/abc369_d 思路:   这道题为什么要用动态规划呢,其实,对于第i个怪物,我们有打与不打两种处理方式,而对于打,我们是获得两倍的经验值,还是一倍的经验值,与我们打了奇数只怪物还是打了偶数只怪物有关了,因此我们定义dp[i][0] 为前i只怪物总共打了偶数次,dp[i][1] 为前i只怪物总

2015 Multi-University Training Contest 5 1009 MZL#39;s Border

MZL's Border  Problem's Link:  http://acm.hdu.edu.cn/showproblem.php?pid=5351   Mean:  给出一个类似斐波那契数列的字符串序列,要你求给出的f[n]字符串中截取前m位的字符串s中s[1...i] = s[s.size()-i+1....s.size()]的最大长度。 analyse:   过计算

【UVa】10600 ACM Contest and Blackout 次小生成树

类型:次小生成树 题目大意: 为了举办ACM竞赛,市长决定给所有的n(3 <= n <= 100)所学校提供可靠的电力供应。当且仅当一个学校直接连到电站,或者连到另一个有可靠供应的学校时,才有可靠供应。现在给出在不同学校之间的布线成本,找出最便宜的两种连线方案。一个方案的成本等于其中所有学校之间连线的成本的总和。 题目分析: 次小生成树。 先求出最小生成树,然后枚举所有不在

【POJ】3660 Cow Contest floyd(可以拓扑排序?)

Cow Contest Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 6925 Accepted: 3792 Description N (1 ≤ N ≤ 100) cows, conveniently numbered 1..N, are participating i