ABC331 A-F 线段树维护字符串哈希

Daiwa Securities Co. Ltd. Programming Contest 2023(AtCoder Beginner Contest 331) - AtCoder

掉大分的一场。D好若至调了好久,EF倒是全都一眼出做法...然而F手搓写bug了直到赛后才找到sb错误...

A - Tomorrow

题意:

每年M月,每个月D天,求y年m月d日的下一天的日期

题解:

void solve()
{
	int m, d, a, b, c;
	scanf("%d%d%d%d%d", &m, &d, &a, &b, &c);
	if (++c > d)
	{
		c = 1;
		if (++b > m)
			b = 1, ++a;
	}
	printf("%d %d %d\n", a, b, c);
}

B - Buy One Carton of Milk

题意:

超市里有盒装鸡蛋,六只装S元,八只装M元,十二只装L元,问购买不少于N个蛋要至少多少元

题解:

简单dp即可

int dp[N];
void solve()
{
	memset(dp, 0x3f, sizeof dp);
	dp[0] = 0;
	int n, s, m, l;
	scanf("%d%d%d%d", &n, &s, &m, &l);
	for (int i = 1; i <= n + 12; ++i)
	{
		if (i >= 6)dp[i] = dp[i - 6] + s;
		if (i >= 8)dp[i] = min(dp[i], dp[i - 8] + m);
		if (i >= 12)dp[i] = min(dp[i], dp[i - 12] + l);
	}
	int ans = INF;
	for (int i = n; i <= n + 12; ++i)
		ans = min(ans, dp[i]);
	printf("%d\n", ans);
}

C - Sum of Numbers Greater Than Me

题意:

给出一个场为N的数组A,问对于每个i输出A中所有大于Ai值的元素之和

题解:

前缀(后缀)和,注意数据会爆int

const int N = 1e6 + 10;
LL a[N], s[N];
void solve()
{
	int n;
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i)
	{
		scanf("%lld", &a[i]);
		s[a[i]] += a[i];
	}
	for (int i = N - 2; i >= 0; --i)
		s[i] += s[i + 1];
	for (int i = 1; i <= n; ++i)
	{
		printf("%lld ", s[a[i] + 1]);
	}
}

D - Tile Pattern

题意:

给出一个N*N的仅由'W'和'B'构成的字符矩阵,它会在平面内无限延展(如样例1的图),给出Q个询问,每个询问需要求出从(a, b)到(c, d)的矩形区域中黑色块('B')的数量

题解:

思路其实很简单,首先计算一片区域内'B'的数量能想到二维前缀和,其次我们可以把这个矩阵分割成几块然后分别求数量然后相加。

在有了以上基础做法之后我们再想如何简单的求出,先把分割出的区域看成9块,然后我们发现左上左下右上右下四块可以拼成一块来计算,左右拼一块,上下拼一块,正中间的一块,然后就这么做,注意细节即可(然后我这个若至就在这里花了40多分钟),这里把N*N的图扩展一下变成2N*2N的图能便于求解

int s[N][N];
int get_sum(int ux, int uy, int vx, int vy)
{
	return s[vx][vy] - s[ux - 1][vy] - s[vx][uy - 1] + s[ux - 1][uy - 1];
}
void solve()
{
	int n, q;
	scanf("%d%d", &n, &q);
	for (int i = 1; i <= n; ++i)
	{
		getchar();
		for (int j = 1; j <= n; ++j)
		{
			s[i][j] = (getchar() == 'B');
			s[i + n][j] = s[i][j + n] = s[i + n][j + n] = s[i][j];
		}
	}
	for (int i = 1; i <= 2 * n; ++i)
	{
		for (int j = 1; j <= 2 * n; ++j)
			s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
	}
	while (q--)
	{
		int ux, uy, vx, vy;
		scanf("%d%d%d%d", &ux, &uy, &vx, &vy);
		++vx, ++vy;
		int tux = ux % n, tvx = vx % n, tuy = uy % n, tvy = vy % n;
		if (tvx < tux)tvx += n;
		if (tvy < tuy)tvy += n;
		//printf("%d %d %d %d\n", tux, tuy, tvx, tvy);
		LL sx = (vx - ux) / n, sy = (vy - uy) / n;
		//printf("%lld %lld\n", sx, sy);
		LL ans = get_sum(tux + 1, tuy + 1, tvx, tvy);
		ans += sx * get_sum(1, tuy + 1, n, tvy);
		ans += sy * get_sum(tux + 1, 1, tvx, n);
		ans += sx * sy * get_sum(1, 1, n, n);
		printf("%lld\n", ans);
	}
}

E - Set Meal

题意:

餐厅给出N主菜,M道配菜,每道主菜的价格是ai,配菜的价格是bi,L中不能搭配在一起的组合ci, di,我们可以选择任意一道主菜+一道配菜(除了前面说的不能组合的)组成套餐,套餐的价格是ai+bi,求套餐价格的最大值

题解:

贪心,先将配菜存成对{价格,编号}然后使它按价格升序,将每个主菜不能搭配的配菜编存入set[i],遍历所有主菜,再从高价到低价遍历配菜,当遇到能做到的搭配时直接计算价格与答案取max然后break即可

int a[N];
PII b[N];
set<int>st[N];
void solve()
{
	int n, m, l;
	scanf("%d%d%d", &n, &m, &l);
	for (int i = 1; i <= n; ++i)
	{
		scanf("%d", &a[i]);
		st[i].clear();
	}
	for (int i = 1; i <= m; ++i)
	{
		scanf("%d", &b[i].first);
		b[i].second = i;
	}
	sort(b + 1, b + 1 + m);
	for (int i = 1; i <= l; ++i)
	{
		int c, d;
		scanf("%d%d", &c, &d);
		st[c].insert(d);
	}
	int ans = 0;
	for (int i = 1; i <= n; ++i)
	{
		for (int j = m; j >= 1; --j)
		{
			if (st[i].find(b[j].second) == st[i].end())
			{
				ans = max(ans, a[i] + b[j].first);
				break;
			}
		}
	}
	printf("%d\n", ans);
}

F - Palindrome Query

题意:

给出一个长度为N的由小写字母构成的字符串以及Q次操作:

1:修改下标为x的字符为c;2:询问子串l, r是否为回文串

题解:

线段树维护字符串哈希,哈希自然溢出就能过

typedef long long LL;
typedef unsigned long long ULL;
const LL N = 1e6 + 10, P = 13331;
#define ls(i) (i<<1)
#define rs(i) (i<<1|1)
#define lh(i) tr[i].lh
#define rh(i) tr[i].rh
#define d(i) tr[i].d
struct node
{
	int d;
	ULL lh, rh;
}tr[N << 2];
ULL p[N];
void push_up(int i)
{
	lh(i) = lh(ls(i)) * p[d(rs(i))] + lh(rs(i));
	rh(i) = rh(ls(i)) + rh(rs(i)) * p[d(ls(i))];
}
void build(int l, int r, int i)
{
	d(i) = r - l + 1;
	if (l == r)
	{
		lh(i) = rh(i) = getchar();
		return;
	}
	int mid = l + r - 1 >> 1;
	build(l, mid, ls(i));
	build(mid + 1, r, rs(i));
	push_up(i);
}
void motify(int pos, int data, int l, int r, int i)
{
	if (l == r)
	{
		lh(i) = rh(i) = data;
		return;
	}
	int mid = l + r - 1 >> 1;
	if (pos <= mid)motify(pos, data, l, mid, ls(i));
	else motify(pos, data, mid + 1, r, rs(i));
	push_up(i);
}
node query_range(int ql, int qr, int l, int r, int i)
{
	if (ql <= l && r <= qr)
		return tr[i];
	int mid = l + r - 1 >> 1;
	if (qr <= mid)return query_range(ql, qr, l, mid, ls(i));
	if (ql > mid)return query_range(ql, qr, mid + 1, r, rs(i));
	node ll = query_range(ql, qr, l, mid, ls(i)), rr = query_range(ql, qr, mid + 1, r, rs(i));
	node res = { ll.d + rr.d, ll.lh * p[rr.d] + rr.lh, ll.rh + rr.rh * p[ll.d] };
	return res;
}
void solve()
{
	int n, q;
	scanf("%d%d", &n, &q);
	getchar();
	p[0] = 1;
	for (int i = 1; i <= n; ++i)
		p[i] = p[i - 1] * P;
	build(1, n, 1);
	while (q--)
	{
		int op;
		scanf("%d", &op);
		if (op == 1)
		{
			int x;
			char c;
			scanf("%d %c", &x, &c);
			motify(x, c, 1, n, 1);
		}
		else
		{
			int l, r;
			scanf("%d%d", &l, &r);
			node t = query_range(l, r, 1, n, 1);
			if (t.lh == t.rh)
				printf("Yes\n");
			else
				printf("No\n");
		}
	}
}

最搞笑的一集,看完题直接出做法然告诉队友之后开始手搓线段树,然后队友去贴板子小修一下直接过了,我写个bug调了20分钟爆金币了

感觉这个写的还蛮好的,以后可以直接当自己的板子用了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值