AtCoder Beginner Contest 326
B - 326-like Numbers
难度: ⭐
题目大意
如果一个三位数的百位和十位的乘积等于个位, 那么这个数就是合法的; 问大于等于n的最小的合法的数是多少;
解题思路
因为数据范围很小, 所以可以直接暴力;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6 + 10;
int n, m, idx;
signed main(){
cin >> m;
while(1){
n = m;
int a = n / 100;
n -= a * 100;
int b = n / 10;
n -= b * 10;
if(a * b == n){
cout << m;
break;
}
m++;
}
return 0;
}
C - Peak
难度: ⭐⭐
题目大意
在一条数轴上有n个礼物, 给定它们的坐标; 你可以选择一个左闭右开的区间, 区间的长度为m; 问这个区间能包含的礼物个数最多是多少;
解题思路
二分加前缀和; 因为最优的情况肯定是区间的左端点恰好在一个礼物上; 所以遍历所有礼物为左端点, 然后用二分找到区间内最右边的那个礼物的坐标, 用前缀和求得数量即可;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6 + 10;
int n, m, idx;
int f[N], p[N];
signed main(){
cin >> n >> m;
for(int i = 1; i <= n; i++){
cin >> f[i];
}
sort(f + 1, f + 1 + n);
int maxn = 0;
for(int i = 1; i <= n; i++){
p[i] = ++idx;
}
for(int i = 1; i <= n; i++){
int x = f[i] + m;
int l = i, r = n;
while(l < r){
int mid = l + r + 1 >> 1;
if(f[mid] >= x) r = mid - 1;
else l = mid;
}
maxn = max(maxn, p[l] - p[i - 1]);
}
cout << maxn;
return 0;
}
D - ABC Puzzle
难度: ⭐⭐⭐
题目大意
给定两个长度为n且由"ABC"组成的字符串s和t; 现在有一个n * n的字符矩阵, 该矩阵有两个要求;
一是: 这个矩阵的每一行和每一列都恰好有1个'A', 1个'B'以及1个'C'; ;
二是: 取这n行中每行最左边的那个字母, 恰好可以组成字符串s; 并且取这n列中每列最上面的那个字母, 恰好可以组成字符串t;
字符矩阵的其他位置为'.'; 输出任意一个满足条件的该矩阵;
解题思路
因为题目要求较为复杂, 并且n的范围最大为5, 所以可以直接考虑暴力; 我们可以暴力枚举所有满足条件一的字符矩阵, 然后再一一检查就可以了; 枚举时的难点主要在于"ABC"的位置选择; 这里我们可以用next_permutation函数进行1~n的全排列; 其中1, 2, 3的位置放'A', 'B', 'C'; dfs构造字符矩阵时可以用n皇后的思路; dfs枚举每一行的情况, 用一个数组表示每一列的"ABC"的存在情况; 这样我们就可以得到一个满足条件一的字符矩阵; 而检查该矩阵也就简单很多了, 只需要按题目说的, 遍历每一行和每一列, 找出最左边和最上边的字符组成的字符串检查一下就可以了;
注意: 这里我踩了一个坑, next_permutation函数的全排列是按字典序来的, 如果当前序列是最大字典序情况就会停止, 如果p数组的初始情况不是12345这样的最小情况, 那么实际上就没有进行完整的全排列, 所以我一层都需要重置p数组; 但是我把p数组设成全局数组了, 这就导致我每一层的dfs都用的同一个数组, 但是每层dfs在全排列时会重置p数组, 所以导致整体都乱了;
神秘代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e3 + 5;
int n, m;
string s, t;
char g[N][N];
int c[N][5];
void check(){
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(g[i][j] != '.'){
if(g[i][j] != s[i - 1]){
return;
}
break;
}
}
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
if(g[j][i] != '.'){
if(g[j][i] != t[i - 1]){
return;
}
break;
}
}
}
cout << "Yes" << endl;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
cout << g[i][j];
}
cout << endl;
}
exit(0);
}
void dfs(int u){
if(u > n){
check();
return;
}
int p[N];
for(int i = 1; i <= n ; i++) p[i] = i;
do{
int pa = 0, pb = 0, pc = 0;
int f = true;
for(int i = 1; i <= n; i++){
if(p[i] == 1){
if(c[i][1]){
f = false;
break;
}
c[i][1] = 1;
g[u][i] = 'A';
pa = i;
}
else if(p[i] == 2){
if(c[i][2] ){
f = false;
break;
}
c[i][2] = 1;
g[u][i] = 'B';
pb = i;
}
else if(p[i] == 3){
if(c[i][3]){
f = false;
break;
}
c[i][3] = 1;
g[u][i] = 'C';
pc = i;
}
else g[u][i] = '.';
}
if(f) {
dfs(u + 1);
}
if(pa) c[pa][1] = 0;
if(pb) c[pb][2] = 0;
if(pc) c[pc][3] = 0;
}while(next_permutation(p + 1, p + 1 + n));
}
signed main(){
cin >> n >> s >> t;
dfs(1);
cout << "No";
return 0;
}
E - Revenge of "The Salary of AtCoder Inc."
难度: ⭐⭐⭐⭐
题目大意
小莫在玩一个骰子游戏, 骰子有n个面; 现在有一个长度为n的数组Ai和一个初始值x = 0; 小莫每回合会掷出一个数y, 如果y > x, 那么小莫就会得到Ay分, 并且让x = y, 然后接着掷骰子, 直到y <= x时退出; 问小莫可获得的分数的期望值是多少, 对mod取模;
解题思路
设dpi是掷到i的总概率, dpi = $\frac{1}{n}$ * $\sum_0^{i-1}$ fj;
$\frac{1}{n}$ * fj表示x = j时骰子显示 i 的概率; 而j可以是0~i-1之间的一个数;
综上所述可以用前缀和+递推来O(n)地解决
神秘代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 3e5 + 10, mod = 998244353;
typedef pair<int, int> PII;
int n, m;
int f[N];
int qmid(int a, int b){
int res = 1;
while(b){
if(b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
signed main(){
cin >> n;
for(int i = 1; i <= n; i++) cin >> f[i];
int res = 0, sum = qmid(n, mod - 2);
for(int i = 1; i <= n; i++){
res = (res + f[i] * sum) % mod;
sum = (sum + sum * qmid(n, mod - 2) % mod) % mod;
}
cout << res;
return 0;
}