2022“杭电杯”中国大学生算法设计超级联赛(4)

给定n个数,\(x\)\(-x\)表示一对括号,正的表示左括号。0可以改成任意括号编号。|括号编号|<=m。问组成括号序列的方案数。
f[0][i][j]表示i-j最外面是一层括号的方案,f[1][i][j]表示i-j由几个括号并列组成的方案

#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
int n, m, a[505], f[2][505][505]; // 0 -> (...) 1-> ()()
inline int mo(int x) { return x >= mod ? x - mod : x; }
int main() {
	int T; scanf("%d", &T);
	while (T--) {
		scanf("%d%d", &n, &m);
		for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
		for (int i = 1; i < n; ++i)
			f[0][i + 1][i] = 1;
		for (int l = 2; l <= n; ++l) {
			for (int i = 1; i + l - 1 <= n; ++i) {
				int j = i + l - 1;
				f[0][i][j] = f[1][i][j] = 0;
				if (a[i] + a[j] == 0) {
					if (a[i] == 0)
						f[0][i][j] = 1ll * m * (f[0][i + 1][j - 1] + f[1][i + 1][j - 1]) % mod;
					else if (a[i] > 0) f[0][i][j] = mo(f[0][i + 1][j - 1] + f[1][i + 1][j - 1]);
				} else if (a[i] == 0 && a[j] < 0 || a[j] == 0 && a[i] > 0) {
					f[0][i][j] = mo(f[0][i + 1][j - 1] + f[1][i + 1][j - 1]);
				}
				for (int k = i; k < j; ++k)
					f[1][i][j] = (1ll * f[0][i][k] * (f[0][k + 1][j] + f[1][k + 1][j]) + f[1][i][j]) % mod;
			}
		}
		printf("%d\n", mo(f[0][1][n] + f[1][1][n]));
	}
	return 0;
}


把0,1,2填入这个样子的图中,使单位三角形三个角上数字和不能是3的倍数,问是否可行。
意会考虑了一下最左边的两列,觉得不可能

BIT Subway

算术题

#include <bits/stdc++.h>
using namespace std;
//const double eps = 1e-7;
int main() {
	int T; scanf("%d", &T);
	while (T--) {
		int n; scanf("%d", &n);
		double s1 = 0, s2 = 0;
		for (int i = 1; i <= n; ++i) {
			double x; scanf("%lf", &x);
			if (s2 < 100) s2 += x;
			else if (s2 < 200) s2 += x * 0.8;
			else s2 += x * 0.5;
			if (s1 + x < 100) s1 += x;
			else {
				if (s1 < 100) {
					x -= 100 - s1;
					s1 = 100;
				}
				if (s1 + x * 0.8 < 200) s1 += x * 0.8;
				else {
					if (s1 < 200) {
						x -= (200 - s1) / 0.8;
						s1 = 200;
					}
					s1 += x * 0.5;
				}
			}				
		}
		printf("%.3lf %.3lf\n", s1, s2);	
	}
	return 0;
}

Climb Stairs

有n层楼,开始在0层,每层只能之多向上跳k层,或向下跳1层,不能重复走。起初有血量a0,每层有ai,只能去ai<=当前血量的层,去了血量增加ai,问能否走遍所有楼
发现跳的形式一定是从x向上到y,然后再向下把y以下的吃完,继续向上。而且容易证明y越低越好。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100000 + 5;
int T, n, k, a[N], LOG[N];
ll hp, suf[N], pre[N], st[N][17];
set<pair<ll, int> > ss;
ll ask(int l, int r) {
	int len = r - l + 1;
	return min(st[l][LOG[len]], st[r - (1 << LOG[len]) + 1][LOG[len]]);
}
int main() {
	for (int i = 2; i <= 100000; ++i) LOG[i] = LOG[i >> 1] + 1;
	int T; scanf("%d", &T);
	while (T--) {
		scanf("%d%lld%d", &n, &hp, &k);
		for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
		suf[n + 1] = 0;
		for (int i = n; i >= 1; --i)
			suf[i] = suf[i + 1] + a[i];
		pre[0] = -1e18;
		for (int i = 1; i <= n; ++i) 
			pre[i] = max(pre[i - 1], a[i] - suf[i + 1]);
		for (int i = 1; i <= n; ++i)
			st[i][0] = pre[i] + suf[i + 1];
		for (int j = 1; j <= 16; ++j)
			for (int i = 1; i + (1 << j) - 1 <= n; ++i)
				st[i][j] = min(st[i][j - 1], st[i + (1 << j - 1)][j - 1]);
		int now = 0, R = 0;
		while (R < n) {
			int l = R + 1, r = min(n, now + k), ret = -1;
			while (l <= r) {
				int mid = l + r >> 1;
				if (ask(l, mid) <= hp) {
					ret = mid;
					r = mid - 1;
				} else
					l = mid + 1;
			}
			if (ret == -1) { now = -1; break; }
			hp += suf[R + 1] - suf[ret + 1];
			now = R + 1;
			R = ret;
		}
		if (now == -1) puts("NO"); else puts("YES");
	}
	return 0;
}

给n个数,每次可以把[l,r]中的数都变成\(a_l xor a_{l+1} xor ... xor a_r\),且保证原数组至少有两个数相等。
答案貌似是所有数能异或出来的最大值。

posted @ 2022-08-05 23:33  chenyilei  阅读(37)  评论(0编辑  收藏  举报