AtCoder Beginner Contest 234题解
AtCoder Beginner Contest 234
比赛的时候过了E,赛后三分钟过了F QAQ
A - Weird Function
题目描述:已知函数\(f(x) = x^2 +2x + 3\),给你一个整数\(t\),求\(f(f(f(t) + t) + f(f(t)))\).
思路:根据题意模拟即可。
时间复杂度:\(O(1)\)
参考代码:
void solve() {
auto f = [](int x)->int {
return x * x + 2 * x + 3;
};
int x(0);
cin >> x;
int res = f(f(f(x) + x) + f(f(x)));
cout << res << '\n';
return ;
}
B - Longest Segment
题目描述:给你\(n\)个二维平面上的点,求任意两点之间的最大距离。
思路:考虑到\(1\leq n \leq 100\),所以直接\(O(n^2)\)暴力即可。
时间复杂度:\(O(n^2)\)
参考代码:
struct Point {
int x, y;
Point(int _x = 0 , int _y = 0):x(_x) , y(_y){}
};
void solve() {
int n;
cin >> n;
vector<Point> points(n);
for (int i = 0; i < n; ++i) cin >> points[i].x >> points[i].y;
double res = 0;
auto cal = [&](const Point& a, const Point& b)->double {
int dx = (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
return sqrt(dx * 1.0);
};
for (int i = 0; i < n; ++i)
for (int j = i + 1; j < n; ++j)
res = max(res, cal(points[i], points[j]));
printf("%.10lf\n", res);
return ;
}
C - Happy New Year!
题目描述:给你一个整数\(K(1 \leq K \leq 10^{18})\),让你求第\(k\)小的只含有0 , 2的字符串。
思路:把\(K\)转化成二进制,然后将二进制中的1换成2即可。
时间复杂度:\(O(logK)\)
参考代码:
void solve() {
long long k = 0;
cin >> k;
string res;
for (int i = 0; i <= 62; ++i) {
if ((k >> i) & 1) res += '2';
else res += '0';
}
while (res.size() > 1 && res.back() == '0') res.pop_back();
reverse(res.begin(), res.end());
cout << res << '\n';
return ;
}
D - Prefix K-th Max
题目描述:给你一个长度为\(N\)的排列和一个整数\(K\),让你输出前缀长度分别为$K + 1 , K + 2 , ... ,N \(的前缀的第\)K$大数。
思路:直接维护一个大小为\(K\)的小根堆即可。
时间复杂度:\(O(nlogn)\)
参考代码:
void solve() {
int n = 0, k = 0;
cin >> n >> k;
vector<int>a(n + 1, 0);
for (int i = 1; i <= n; ++i) cin >> a[i];
priority_queue<int, vector<int>, greater<int>>heap;
for (int i = 1; i < k; ++i) heap.push(a[i]);
for (int i = k; i <= n; ++i) {
if (heap.size() < k) heap.push(a[i]);
else if (heap.top() < a[i]) {
heap.pop();
heap.push(a[i]);
}
cout << heap.top() << '\n';
}
return ;
}
E - Arithmetic Number
题目描述:给你一个整数\(x\;(1 \leq x \leq 10^{17})\),让你求不小于\(x\)且最小的整数\(S\)满足下列条件:
假设\(S\)有\(n\)位且\(S_i\)表示\(S\)的第\(i\)个数字,则\(S_2 - S_1 = S_3 - S_2 = .. = S_n - S_{n - 1}\)
思路:考虑到\(x\)最多只有\(17\)位,考虑暴力枚举第一个数字和公差构造一个长度与\(x\)相同的数字并判断与\(x\)的大小关系并更新答案即可,答案最大为\(n + 1\)个\(1\)。
时间复杂度:\(O(9\times 16 \times n)\)
参考代码:
void chkmin(string& s, string& t) {
if (s.size() > t.size()) s = t;
else s = min(s, t);
return;
}
void solve() {
string s;
cin >> s;
string res;
int n = s.size();
for (int i = 1; i <= n + 1; ++i) res += '1';
for (int i = 1; i <= 9; ++i) {
for (int d = -8; d <= 8; ++d) {
string t;
t += (char)('0' + i);
int last = i;
for (int j = 2; j <= n; ++j) {
if (d + last > 9 || d + last < 0) break;
last = d + last;
t += (char)('0' + last);
}
if (t.size() < n) continue;
if (t < s) continue;
chkmin(res, t);
}
}
cout << res << '\n';
return ;
}
F - Reordering
题目描述:给你一个长度为\(n\)的只含有小写字母的字符串\(s\),对于它的所有子串的排列数的总和是多少。
数据范围:\(1 \leq n \leq 5000\)。
思路:考虑先按照字符进行统计,则最多有\(26\)种字符,定义状态\(f_{i , j}\)表示以第\(i\)个字符结尾的长度为\(j\)的方案数。对于相同的字符,我们直接枚举每次取多少个与前面不相同的字符对答案进行贡献。假设我们枚举到第\(k\)种字符,且前面\(k - 1\)种字符共有\(len\)个,那么当前枚举第\(k\)种字符的第\(r\)个时,状态转移为:
答案为\(\sum\limits_{i = 1}^{n} f_{n , i}\)
对于\(j \neq 0\)时的转移做如下解释:考虑当前有一个长度为\(len\)的字符串且没有字符与当前枚举的字符相同,然后要插入\(r\)个当前枚举的字符,根据组合数学可知方案数为\(\frac{(len + r)!}{(len)!r!}\) ,该长度为\(len\)的字符串有\(f[len , j]\)个,故对答案的贡献就是将二者相乘。
时间复杂度:阶乘可以\(O(n)\)预处理,然后求逆元需要\(O(log\;mod)\),枚举不同字符的复杂度是\(O(n^2)\)的,故总的复杂度为:\(O(n^2log\;mod + n)\)
参考代码:
const int mod = 998244353;
int quickPow(int a, int p) {
int res = 1;
while (p) {
if (p & 1) res = 1ll * res * a % mod;
a = 1ll * a * a % mod;
p >>= 1;
}
return res;
}
void solve() {
string s;
cin >> s;
vector<int>cnt(27, 0);
for (auto c : s) cnt[c - 'a' + 1]++;
int n = s.size();
vector<int>p(n + 10, 0);
p[0] = 1;
for (int i = 1; i <= n + 5; ++i) p[i] = 1ll * p[i - 1] * i % mod;
vector<vector<int>>f(n + 1, vector<int>(n + 1 , 0));
//表示以第i个字符结尾 长度为j的方案数
int len = 0;
for (int k = 1; k <= 26; ++k) {
if (cnt[k] == 0) continue;
int newlen = len;
for (int r = 1; r <= cnt[k]; ++r) {
int i = r + len;
for (int j = 0; j <= len; ++j) {
long long dx = f[len][j];
f[i][j + r] += dx * p[j + r] % mod
* quickPow(1ll * p[r] * p[j] % mod, mod - 2) % mod;
if (j == 0) f[i][j + r] = 1;
}
for (int j = 1; j <= r + len; ++j) f[r + len][j] = (f[r + len][j] + f[r + len - 1][j]) % mod;
}
len += cnt[k];
}
int res = 0;
for (int i = 1; i <= n; ++i) res = (res + f[n][i]) % mod;
cout << res << '\n';
return ;
}
作者:cherish.
出处:https://home.cnblogs.com/u/cherish-/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。