デンソークリエイトプログラミングコンテスト2023(AtCoder Beginner Contest 309) - AtCoder
A - Nine
题意:
有这样一个3*3的表格(如下图),给定两个数A,B(1<=A<B<=9),问AB是否左右相邻
题解:
...水题
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 2e2 + 10, INF = 0x3f3f3f3f;
void solve()
{
int a, b;
scanf("%d%d", &a, &b);
if (a % 3 && a + 1 == b)
printf("Yes\n");
else
printf("No\n");
}
int main()
{
int T = 1;
//scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
B - Rotate
题意:
给定一个n行n列的由01组成的表,将这个表的最外面一圈顺时针移动一格
题解:
模拟
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 1e2 + 10, INF = 0x3f3f3f3f;
char a[N][N], b[N][N];
void solve()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
scanf("%s", a[i] + 1);
for (int j = 1; j <= n; ++j)
b[i][j] = a[i][j];
}
for (int i = 2, j = n - 1; i <= n; ++i, --j)
{
a[1][i] = b[1][i - 1];
a[i][n] = b[i - 1][n];
a[n][j] = b[n][j + 1];
a[j][1] = b[j + 1][1];
}
for (int i = 1; i <= n; ++i)
printf("%s\n", a[i] + 1);
}
int main()
{
int T = 1;
//scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
C - Medicine
题意:
高桥桑要吃n种药,每种药需要在前ai天每天吃bi颗,问从哪天开始每天需要吃的药少于k颗
题解:
做法应该很多,我直接map偷懒
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 3e5 + 10, INF = 0x3f3f3f3f;
map<int, LL>mp;
void solve()
{
LL n, k, s = 0;
scanf("%lld%lld", &n, &k);
for (int i = 1; i <= n; ++i)
{
int x, y;
scanf("%d%d", &x, &y);
mp[x] += y;
s += y;
}
mp[0] = 0;
for (auto& i : mp)
{
s -= i.second;
if (s <= k)
{
printf("%d\n", i.first + 1);
return;
}
}
}
int main()
{
int T = 1;
//scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
D - Add One Edge
题意:
给出两个连通图,点个数分别为n1,n2(两个连通图内点的编号分别为1到n1和n1+1到1n1+n2),边共m条。问在两个连通图间连一条边之后点1到点n1+n2之间的最短路径(边个个数)。
题解:
先对两个连通图分别广搜求出到点1(或点n1+n2)的最短路径的最大值,相加之后+1即可
(下方代码里的dist[i]不是最短距离,是最短距离+1,所以最后答案实际上是mx1-1+mx2-1+1)
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 3e5 + 10, INF = 0x3f3f3f3f;
vector<int>e[N];
int dist[N];
void bfs(int sta)
{
queue<int>q;
dist[sta] = 1;
q.push(sta);
while (q.size())
{
int u = q.front();
q.pop();
for (auto v : e[u])
{
if (!dist[v])
{
dist[v] = dist[u] + 1;
q.push(v);
}
}
}
}
void solve()
{
int n1, n2, m;
scanf("%d%d%d", &n1, &n2, &m);
for (int i = 1; i <= m; ++i)
{
int u, v;
scanf("%d%d", &u, &v);
e[u].push_back(v);
e[v].push_back(u);
}
bfs(1);
bfs(n1 + n2);
int mx1 = 0, mx2 = 0;
for (int i = 1; i <= n1; ++i)
mx1 = max(mx1, dist[i]);
for (int i = n1 + 1; i <= n1 + n2; ++i)
mx2 = max(mx2, dist[i]);
printf("%d\n", mx1 + mx2 - 1);
}
int main()
{
int T = 1;
//scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
E - Family and Insurance
题意:
有一个家族前来买保险,这个家族有n个成员,给定n-1个pi(pi<i),表示人i的父亲是pi(i从2开始),这个家族买了m份保险,第i个保险能从人xi开始传yi代(本人及往下的前yi代都能享受到保险),问有多少人享受保险。
题解:
树形dp?记h[i]为人i的保险还能传递h[i]-1代,先存入所有第一代保险的享受者的最大传递次数h[xi]=max(h[xi],yi+1),从祖先开始进行一个深搜,如果h[i]>0说明这个人享受到了保险,然后把保险传给下一代,将下一代的保险传递的深度与h[i]-1取max...(写的好懒,不如直接看代码...)
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 3e5 + 10, INF = 0x3f3f3f3f;
int p[N], h[N];
vector<int>kids[N];
int dfs(int u)
{
int s = 0;
if (h[u])++s;
for (auto v : kids[u])
{
h[v] = max(h[v], h[u] - 1);
s += dfs(v);
}
return s;
}
void solve()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 2; i <= n; ++i)
{
scanf("%d", &p[i]);
kids[p[i]].push_back(i);
}
for (int i = 1; i <= m; ++i)
{
int x, y;
scanf("%d%d", &x, &y);
h[x] = max(h[x], y + 1);
}
printf("%d", dfs(1));
}
int main()
{
int T = 1;
//scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
F - Box in Box
题意:
有n个箱子,每个箱子的长宽高分别为hi,wi,di,问是否存在两个箱子,通过必要时进行旋转,使得一个箱子的长宽高分别严格大于另一个箱子的长宽高。
题解:
离散化线段树。先对hi,wi,di排序,使得hi<=wi<=di(相当于提前旋转好了),考虑先对于hi升序排序,这样能保证在i<j时,只需要在1到i的集合中找到wi<wj&&di<dj(为了避免hi==hj,可以将相等的元素延迟加入),开一个维护最小值的线段树,通过线段树寻找w值在1到wj-1范围内的di的最小值(不存在则为初始化的INF),若di的最小值小于dj,则存在i的长宽高均严格小于j的长宽高。
(赛后补的,抄的官解的做法...)
#define _CRT_SECURE_NO_WARNINGS
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const LL N = 2e5 + 10, INF = 0x3f3f3f3f;
struct node
{
int x, y, z;
bool operator<(const node X)const
{ //按hi升序
return x < X.x;
}
}a[N];
int tr[4 * N];
vector<int>v;
queue<int>q;
void updata(int w, int data, int l, int r, int idx)
{
if (l == r)
{
tr[idx] = min(tr[idx], data);
return;
}
int mid = l + r >> 1;
if (w <= v[mid])updata(w, data, l, mid, idx << 1);
else updata(w, data, mid + 1, r, idx << 1 | 1);
tr[idx] = min(tr[idx << 1], tr[idx << 1 | 1]);
}
int query_range(int w, int l, int r, int idx)
{
if (v[r] < w)
return tr[idx];
int mid = l + r >> 1;
int minn = query_range(w, l, mid, idx << 1);
if (v[mid + 1] < w)
minn = min(minn, query_range(w, mid + 1, r, idx << 1 | 1));
return minn;
}
void solve()
{
memset(tr, 0x3f, sizeof tr);//初始化线段树
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
int l[5];
for (int j = 1; j <= 3; ++j)
scanf("%d", &l[j]);
sort(l + 1, l + 4);//使hi<=wi<=di
a[i].x = l[1];
a[i].y = l[2];
a[i].z = l[3];
v.push_back(l[2]);
}
sort(a + 1, a + 1 + n);
v.push_back(0);
sort(v.begin(), v.end());//对wi的值进行离散化
v.erase(unique(v.begin(), v.end()), v.end());
for (int i = 1; i <= n; ++i)
{
q.push(i);//延迟相等情况的加入
while (a[q.front()].x < a[i].x)
{
updata(a[q.front()].y, a[q.front()].z, 0, v.size() - 1, 1);
q.pop();
}
int minn = query_range(a[i].y, 0, v.size() - 1, 1);
if (minn < a[i].z)
{
printf("Yes\n");
return;
}
}
printf("No\n");
}
int main()
{
int T = 1;
//scanf("%d", &T);
while (T--)
{
solve();
}
return 0;
}
G不会捏