2023-03-04 22:36阅读: 594评论: 1推荐: 2

AtCoder Beginner Contest 292

A - CAPS LOCK (abc292 a)

题目大意

给定一个小写字母串,将其转换成大写字母。

解题思路

调库,或者按照ascii码转换即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
string s;
cin >> s;
for(auto &i : s)
i = toupper(i);
cout << s << endl;
return 0;
}


B - Yellow and Red Card (abc292 b)

题目大意

n个人, m个事件,分三种:给某人黄牌,给某人红牌,问某人是否被罚下场。

如果一人被罚两张黄牌或一张红牌则被罚下场。

回答每个询问。

解题思路

按照题意,维护每个人的黄牌和红牌数量模拟即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n, q;
cin >> n >> q;
vector<vector<int>> cnt(2, vector<int>(n, 0));
while(q--){
int c, x;
cin >> c >> x;
c --;
x --;
if (c == 2){
if (cnt[0][x] < 2 && cnt[1][x] < 1)
cout << "No" << '\n';
else
cout << "Yes" << '\n';
}else
cnt[c][x] ++;
}
return 0;
}


C - Four Variables (abc292 c)

题目大意

给定n,问有多少正整数组(A,B,C,D),满足 AB+CD=n

解题思路

给定X,预处理AB=X 的方案数cnt[X]

然后枚举AB的乘积 X,则 CD的乘积为 nX,其两个方案数相乘cnt[X]×cnt[nX]。然后累加即是答案。

时间复杂度为 O(nlogn)

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n;
cin >> n;
vector<int> cnt(n + 1);
for(int i = 1; i <= n; ++ i)
for(int j = 1; j <= n; ++ j){
if (1ll * i * j > n)
break;
cnt[i * j] ++;
}
LL ans = 0;
for(int i = 1; i < n; ++ i)
ans += 1ll * cnt[i] * cnt[n - i];
cout << ans << '\n';
return 0;
}


D - Unicyclic Components (abc292 d)

题目大意

给定一张无向图,问每个连通块是否满足:其边数点数相等。

解题思路

并查集维护连通性,同时维护连通块的边数点数,最后一一判断即可。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
class dsu {
public:
vector<int> p;
vector<int> psz;
vector<int> esz;
int n;
dsu(int _n) : n(_n) {
p.resize(n);
psz.resize(n);
esz.resize(n);
iota(p.begin(), p.end(), 0);
fill(psz.begin(), psz.end(), 1);
fill(esz.begin(), esz.end(), 0);
}
inline int get(int x) {
return (x == p[x] ? x : (p[x] = get(p[x])));
}
inline bool unite(int x, int y) {
x = get(x);
y = get(y);
esz[y] ++;
if (x != y) {
p[x] = y;
psz[y] += psz[x];
esz[y] += esz[x];
return true;
}
return false;
}
inline bool check(){
for(int i = 0; i < p.size(); ++ i){
if (get(i) == i && psz[i] != esz[i]){
return false;
}
}
return true;
}
};
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n, m;
cin >> n >> m;
dsu d(n);
for(int i = 0; i < m; ++ i){
int u, v;
cin >> u >> v;
-- u, -- v;
d.unite(u, v);
}
if (d.check())
cout << "Yes" << '\n';
else
cout << "No" << '\n';
return 0;
}


E - Transitivity (abc292 e)

题目大意

给定一张有向图。如果对于三个点(a,b,c)a>bb>c,则必须有边a>c

问最少添加多少条边,使得对于任意三个点,都满足以上性质。

解题思路

考虑一条链,从左连到右,容易发现左边的点与右边的每个点都要连一条边。

即从一个点出发,它能到达的所有点,在最终的图都要与其连边。

因此从每个点BFS,求得其能到达的所有点数。对所有点累加即是最终图的边数,减去已有的边数,则是需要添加的最小边数。

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n, m;
cin >> n >> m;
vector<vector<int>> edge(n);
for(int i = 0; i < m; ++ i){
int u, v;
cin >> u >> v;
-- u, -- v;
edge[u].push_back(v);
}
int ans = 0;
auto bfs = [&](int st){
queue<int> team;
team.push(st);
int cnt = 0;
vector<int> visit(n, 0);
visit[st] = 1;
while(!team.empty()){
auto u = team.front();
team.pop();
for(auto &v : edge[u]){
if (!visit[v]){
++ cnt;
team.push(v);
visit[v] = 1;
}
}
}
return cnt;
};
for(int i = 0; i < n; ++ i)
ans += bfs(i);
ans -= m;
cout << ans << '\n';
return 0;
}


F - Regular Triangle Inside a Rectangle (abc292 f)

题目大意

给定一个矩阵,问其内接的最大正三角形的边长是多少。

解题思路

从样例的图我们可以进行猜测:

  • 三角形的一个顶点在矩形的顶点上
  • 当矩形的长不够长时,三角形的另外两个点都在矩形的边上。

example

15的角为 θ,矩形长a,宽 ba>b),三角形边长 x,根据正三角形边相等和高中数学知识可得

x=acosθ=bcos(30θ)

用和角公式将cos(30θ)拆开,然后解方程得到

tanθ=2ba3

因为这里0θ30,所以 tanθ应该大于 0。因此这里就有个边界条件 2ba>3

一旦不满足,说明长 a太大了,此时三角形最大的情况,就是其高和矩形的宽相等,即三角形的边长就是 x=2b3

否则,算得cosθ=11+tan2θx=acosθ

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int a, b;
cin >> a >> b;
if (a < b)
swap(a, b);
long double sq3 = sqrt(3);
if (2.0 * b / a < sq3){
double x = b / sq3 * 2;
cout << fixed << setprecision(15) << x << '\n';
}else {
long double tan = 2.0 * b / a - sq3;
long double cos = sqrt(1 / (1 + tan * tan));
long double x = a / cos;
cout << fixed << setprecision(15) << x << '\n';
}
return 0;
}


G - Count Strictly Increasing Sequences (abc292 g)

题目大意

给定n个长度为 m的包含数字和 ?的字符串。

将这些 ?替换数字。问有多少种替换方案,满足s0<s1<s2<...<sn1

解题思路

应该是个数位DP竟然是区间DP

首先数的大小可以转换成字典序大小的比较。

状态切分点来源于字典序大小的定义的递归性: s<t,当且仅当 s[0]<t[0],或者 s[0]=t[0]s[1..m]<t[1..m],而 s[1..m]<t[1..m]可以看成原问题s<t(或者可以看成 s[0...m]<t[0...m])的一个子问题。

因此,我们考虑要确保s0<s1<s2<...<sn1,那首先会有前k个串,其第一个数字是相同的,假设为f,即s0[0]=s1[0]=s2[0]=...=sk1[0]=f

此时问题就转换成:前k个串的后 m1个数字的满足题目条件的方案数,与,后面串的 m个数字的满足题目条件,且第一个数字要大于f的方案数,的乘积。

即设dp[l][r][k][f]表示区间 [l,r]的字符串,考虑[k..m1]的位置, 且第k个数字是大于等于 f的,满足题目条件的方案数。

那么原问题是 dp[0][n1][0][0],当前k个串的第一个数字都是 l时(这意味着后面串的第一个数字要大于l),原问题就切分成两部分的乘积: dp[0][k1][1][0]×dp[k][n1][0][l+1]

根据字典序大小的递归定义,第一项就是s[0]=t[0]s[1..m]<t[1..m]的情况,第二项就是s[0]<t[0]的情况,都是满足s<t的条件。

由此枚举k转移即可,写成 dfs就不用脑子了,注意下边界条件。

状态复杂度是O(10n2m),转移是 O(n),总复杂度是 O(10n3m)

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int mo = 998244353;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n, m;
cin >> n >> m;
vector<string> s(n);
for(auto &i : s)
cin >> i;
vector<vector<vector<vector<int>>>> dp(n, vector<vector<vector<int>>>(n, vector<vector<int>>(m, vector<int>(10, -1))));
function<int(int, int, int, int)> dfs = [&](int l, int r, int k, int f){
if (k == m)
return int(l == r);
if (l > r)
return 1;
if (f >= 10)
return 0;
if (dp[l][r][k][f] != -1)
return dp[l][r][k][f];
int val = dfs(l, r, k, f + 1);
for(int i = l; i <= r; ++ i){
if (s[i][k] != '?' && s[i][k] != '0' + f)
break;
val = val + 1ll * dfs(l, i, k + 1, 0) * dfs(i + 1, r, k, f + 1) % mo;
val %= mo;
}
return dp[l][r][k][f] = val;
};
int ans = dfs(0, n - 1, 0, 0);
cout << ans << '\n';
return 0;
}


Ex - Rating Estimator (abc292 h)

题目大意

给定n场比赛的表现分ai,经过第 k 场比赛后,rating将变成 i=1kaik 。但当rating超过 B后便不再涨了。

处理一下 q次操作,输出每次操作完后,经过这 n场比赛最后的 rating值。

每次操作给定 c,x,将第 c场比赛的 表现分 ac更改为 x

操作是持久化的。

解题思路

先考虑不修改的,这里用到一个转换技巧跟abc236 E一样。

我们要找i=1kaik>B,即i=1kaikB>0,即i=1k(aiB)>0

即对于新数组bi=aiB,原问题找最小的 k使得a满足上述条件,就转换成找最小的k使得 b满足前缀和大于 0

维护前缀和的最大值,然后二分查找。

考虑修改的话,用线段树维护这个前缀和的最大值,然后在线段树上二分就可以了。复杂度不变,都是O(qlogn)

神奇的代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
class segtree {
#define lson (root << 1)
#define rson (root << 1 | 1)
int n;
vector<LL> sum;
vector<LL> max;
void build(int root, int l, int r, const vector<LL> &v) {
if (l == r) {
sum[root] = v[l - 1];
max[root] = v[l - 1];
return;
}
int mid = (l + r) >> 1;
build(lson, l, mid, v);
build(rson, mid + 1, r, v);
sum[root] = sum[lson] + sum[rson];
max[root] = std::max(max[lson], sum[lson] + max[rson]);
}
void update(int root, int l, int r, int pos, LL val){
if (l == r){
sum[root] = val;
max[root] = val;
return;
}
int mid = (l + r) >> 1;
if (pos <= mid)
update(lson, l, mid, pos, val);
else
update(rson, mid + 1, r, pos, val);
sum[root] = sum[lson] + sum[rson];
max[root] = std::max(max[lson], sum[lson] + max[rson]);
}
pair<int, LL> query(int root, int l, int r, LL presum){
if (l == r)
return {l, presum + max[root]};
int mid = (l + r) >> 1;
if (presum + max[lson] >= 0)
return query(lson, l, mid, presum);
else
return query(rson, mid + 1, r, presum + sum[lson]);
}
public:
void build(const vector<LL> &v){
n = v.size();
sum.resize(4 * (n + 1), 0);
max.resize(4 * (n + 1), 0);
build(1, 1, n, v);
}
void update(int pos, LL val){
assert(1 <= pos && pos <= n);
update(1, 1, n, pos, val);
}
pair<int, LL> query(){
return query(1, 1, n, 0);
}
};
int main(void) {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int n, q;
LL b;
cin >> n >> b >> q;
vector<LL> a(n);
for(auto &i : a){
cin >> i;
i -= b;
}
segtree seg;
seg.build(a);
while(q--){
int c;
LL x;
cin >> c >> x;
seg.update(c, x - b);
auto [pos, sum] = seg.query();
double ans = b + 1.0 * sum / pos;
cout << fixed << setprecision(15) << ans << '\n';
}
return 0;
}


本文作者:~Lanly~

本文链接:https://www.cnblogs.com/Lanly/p/17179400.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   ~Lanly~  阅读(594)  评论(1编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.