C130【?XXXX级】0321 ?组测试

发布时间 2023-03-22 21:10:44作者: 煎饼Li

欢迎到学校的OJ去切题QWQ

他妈的,来DP全家桶是吧

Problem A

T1

非常的Simple啊。

我们考虑\(dp_i\)为当前到第\(i\)个数的时候能得到的最大值。

\(dp_i=max(dp_{i-1},dp_{i-2}+a_i)\)

要么我们选不了当前这个数,沿用上一个数的时候的最大值;要么就更新。

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int dp[N], a[N];
int n, t;

int read()
{
	int x = 0, w = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9')
	{
		if (ch == '-')
			w = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9')
	{
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * w;
}

void clear()
{
	memset(dp, 0, sizeof dp);
	n = 0;
}

void solve()
{
	clear();
	n = read();
	for (int i = 1; i <= n; i++)
		a[i] = read();
		
	dp[1] = a[1], dp[2] = max(a[1], a[2]);
	
	for (int i = 3; i <= n; i++)
		dp[i] = max(dp[i - 1], dp[i - 2] + a[i]);
		
	printf("%d\n", dp[n]);
}

int main()
{
	t = read();
	
	while (t--)
		solve();
		
	return 0;
}

Problem B

T2

很搞笑啊。为什么不尊重原题把原题目给复制过来啊?非得自己改一个名字,这台麻烦哦了

链接:https://ac.nowcoder.com/acm/contest/11171/B

来源:牛客网

设dp[i, j]表示i到j区间任取两个数能够异或出来的最大值,初始化dp[i, j] = a[i] ^ a[j]。

转移方程就是:\(dp_{i,j} = max(dp_{i,j}, dp_{i+1,j}, dp_{i,j-1})\)

#include <bits/stdc++.h>

using namespace std;

const int N = 5e3 + 10;

int f[N][N];
int a[N];
int n, m, l, r;

int read()
{
	int x = 0, w = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9')
	{
		if (ch == '-')
			w = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9')
	{
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * w;
}

int main()
{
	n = read(), m = read();
	for (int i = 1; i <= n; i++)
		a[i] = read();
		
	for (int i = 1; i <= n; i++)
	{
		f[i][i] = a[i];
		for (int j = 1; j <= n; j++)
			f[i][j] = a[i] ^ a[j];
	}
	
	for (int i = n; i >= 1; i--)
		for (int j = i + 1; j <= n; j++)
			f[i][j] = max({f[i][j], f[i][j - 1], f[i + 1][j]});
			
	for (int i = 1; i <= m; i++)
	{
		l = read(), r = read();
		printf("%d\n", f[l][r]);
	}
	
	return 0;
}

Problem C

T3

非常的Simple啊。

正解是DP和贪心。但是DP我不想不会写,于是就写个simple的贪心吧。

我们只需要考虑它是往左倒还是往右倒。而且,头和尾的两个是必砍倒得(他们肯定可以往左右中的一个方向倒)。

如果小于两棵树,那就直接输出树的棵数(不解释)。

现在就判断往左倒行不行。如果小于上一棵树的位置就不行,否则就计数器(可砍的树+1)。再判断往右倒行不行。如果行,计数器+1,并且把右面倒下的位置给占了(方便下次判断)。

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;

int x[N], h[N];
bool vis[N];
int n, res;

int read()
{
	int x = 0, w = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9')
	{
		if (ch == '-')
			w = -1;
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9')
	{
		x = x * 10 + ch - '0';
		ch = getchar();
	}
	return x * w;
}

int main()
{
	n = read();
	for (int i = 1; i <= n; i++)
		x[i] = read(), h[i] = read();
	if (n <= 2)
		printf("%d\n", n);
	else
	{
		res = 2;
		for (int i = 2; i <= n - 1; i++)
			if (x[i] - h[i] > x[i - 1])
				res++;
			else if (x[i] + h[i] < x[i + 1])
			{
				res++;
				x[i] += h[i];
			}
		printf("%d\n", res);
	}
	return 0;
}

Problem D

T4

未完待续……