ABC309 A-F

デンソークリエイトプログラミングコンテスト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不会捏

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值