2022-02-24每日刷题打卡

229 阅读6分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

2022-02-24每日刷题打卡

一本通——动态规划

1286:怪盗基德的滑翔翼

【题目描述】

怪盗基德是一个充满传奇色彩的怪盗,专门以珠宝为目标的超级盗窃犯。而他最为突出的地方,就是他每次都能逃脱中村警部的重重围堵,而这也很大程度上是多亏了他随身携带的便于操作的滑翔翼。

有一天,怪盗基德像往常一样偷走了一颗珍贵的钻石,不料却被柯南小朋友识破了伪装,而他的滑翔翼的动力装置也被柯南踢出的足球破坏了。不得已,怪盗基德只能操作受损的滑翔翼逃脱。

假设城市中一共有N幢建筑排成一条线,每幢建筑的高度各不相同。初始时,怪盗基德可以在任何一幢建筑的顶端。他可以选择一个方向逃跑,但是不能中途改变方向(因为中森警部会在后面追击)。因为滑翔翼动力装置受损,他只能往下滑行(即:只能从较高的建筑滑翔到较低的建筑)。他希望尽可能多地经过不同建筑的顶部,这样可以减缓下降时的冲击力,减少受伤的可能性。请问,他最多可以经过多少幢不同建筑的顶部(包含初始时的建筑)?

【输入】

输入数据第一行是一个整数K(K<100)K(K<100),代表有KK组测试数据。

每组测试数据包含两行:第一行是一个整数N(N<100)N(N<100),代表有NN幢建筑。第二行包含NN个不同的整数,每一个对应一幢建筑的高度h(0<h<10000)h(0<h<10000),按照建筑的排列顺序给出。

【输出】

对于每一组测试数据,输出一行,包含一个整数,代表怪盗基德最多可以经过的建筑数量。

【输入样例】

3 
8
300 207 155 299 298 170 158 65 
8 
65 158 170 298 299 155 207 300 
10 
2 1 3 4 5 6 7 8 9 10
【输出样例】
6 
6
9

虽然说越飞越低,但这题不是单纯的求递减序列,题目说了,可以以任意一个点,任意一个方向出发,也就是说,如果我们从第一个元素向右出发,求得就是最长递减序列,但如果我们从末尾元素向左出发,那我们要求的就是递增序列。我们要分别求出这两个序列的长度,输出大的哪一方。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<string.h>
#include<string>
#include<unordered_map>
#include<math.h>
#include<queue>
#include<stack>

const int N = 1010;
int f[N], h[N], d[N];

int main()
{
	int n,m;
	cin >> m;
	while (m--)
	{
		cin >> n;
		for (int i = 0; i < n; i++)
			cin >> h[i];
		f[0] = 1;
		d[0] = 1;
		int res = 0;
		for (int i = 1; i < n; i++)
		{
			f[i] = 1;
			for (int j = i - 1; j >= 0; j--)
			{
				if (h[i] > h[j])
				{
					f[i] = max(f[i], f[j] + 1);
					
				}
				
			}
			res = max(res, f[i]);
		}
		for (int i = n - 1; i >= 0; i--)
		{
			d[i] = 1;
			for (int j = i + 1; j < n; j++)
			{
				if (h[i] > h[j])
				{
					d[i] = max(d[i], d[j] + 1);
					
				}
			}
			res = max(res, d[i]);
		}
		cout << res << endl;
	}
		
	return 0;
}

1287:最低通行费

【题目描述】

一个商人穿过一个N×N的正方形的网格,去参加一个非常重要的商务活动。他要从网格的左上角进,右下角出。每穿越中间1个小方格,都要花费1个单位时间。商人必须在(2N-1)个单位时间穿越出去。而在经过中间的每个小方格时,都需要缴纳一定的费用。

这个商人期望在规定时间内用最少费用穿越出去。请问至少需要多少费用?

注意:不能对角穿越各个小方格(即,只能向上下左右四个方向移动且不能离开网格)。

【输入】

第一行是一个整数,表示正方形的宽度N (1≤N<100);

后面N行,每行N个不大于100的整数,为网格上每个小方格的费用。

【输出】

至少需要的费用。

【输入样例】

5

1 4 6 8 10

2 5 7 15 17

6 8 9 18 20

10 11 12 19 21

20 23 25 29 33

【输出样例】

109

【提示】

样例中,最小值为109=1+2+5+7+9+12+19+21+33。

从左上角出发,开始dp,除了最顶层和最左边的边界,f[i] [j]的状态转移方程为max(f[i-1] [j],f[i] [j-1]);f[i] [j]的状态设定是:到达[i] [j]位置所需要的最少花费。每次对比当前格子的上方和前方,看哪个格子的值最小,把小的一方加到自己身上(即看从哪个格子到自己格子所用费用最少)。最后输出最右下角的格子的值。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<string.h>
#include<string>
#include<unordered_map>
#include<math.h>
#include<queue>
#include<stack>

const int N = 1010;
int f[N][N];

int main()
{
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
		{
			cin >> f[i][j];
			if (i == 0 && j > 0)f[i][j] += f[i][j - 1];
			else if (j == 0 && i > 0)f[i][j] += f[i - 1][j];
		}
	for (int i = 1; i < n; i++)
	{
		for (int j = 1; j < n; j++)
		{
			f[i][j] += min(f[i - 1][j], f[i][j - 1]);
		}
	}
	cout << f[n-1][n-1] << endl;
	return 0;
}

CODEFORCES

A. Hard Way

Sam lives in Awesomeburg, its downtown has a triangular shape. Also, the following is true about the triangle:

  • its vertices have integer coordinates,
  • the coordinates of vertices are non-negative, and
  • its vertices are not on a single line.

He calls a point on the downtown’s border (that is the border of the triangle) safe if he can reach this point from at least one point of the line y=0y=0 walking along some straight line, without crossing the interior of the triangle.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a38uCAuZ-1645685216406)(espresso.codeforces.com/3af75fe0f0a… the picture the downtown is marked with grey color. The first path is invalid because it does not go along a straight line. The second path is invalid because it intersects with the interior of the downtown. The third and fourth paths are correct.

Find the total length of the unsafe parts of the downtown border. It can be proven that these parts are segments and their number is finite.

Input

Each test contains multiple test cases. The first line contains a single integer tt (1≤t≤10001≤t≤1000) — the number of test cases. Description of the test cases follows.

Each test case contains three lines, each of them contains two integers xixi, yiyi (0≤xi,yi≤1090≤xi,yi≤109) — coordinates of the vertices of the downtown’s border.

Output

For each test case print a single number — the answer to the problem.

Your answer will be considered correct if its absolute or relative error does not exceed 10−910−9. Formally let your answer be aa, jury answer be bb. Your answer will be considered correct if |a−b|max(1,|b|)≤10−9|a−b|max(1,|b|)≤10−9.

Example

input

5
8 10
10 4
6 2
4 6
0 1
4 2
14 1
11 2
13 2
0 0
4 0
2 4
0 1
1 1
0 0

output

0.0000000
0
2.0000
0.00
1

这题意思就是说,给你一个三角形的三个点,问,你这个三角形的三条边,有没有能不被从x轴延申出来的直线碰到的。这个直线不能穿过三角形也不能是弯曲的。可能你还有点懵,这道题换个人话说就是,这三角形有没有哪一条边是和x轴平行的,且这条边要处在上方,(即形成一个倒三角的样子)。因为如果这条边和x轴平行,那么即时x轴和这条边无限延长也不会有交点,而因为从x轴出来的直线想要到达这个边就必须穿过三角形,显然是不和规则的。也就是说我们要求出这个三角形的最顶上的边能否和x轴平行,如果可以,输出这条边的长度,不可以就输出0。

我们就先求出三角形上面的边(取y坐标最大的两个点),然后算这条边的斜率:(y2-y1)/(x2-x1),但我们既然只看是否为0,那我们就看y2-y1是否为0即可,如果为0就输出两个点之间的距离(不用那么麻烦,因为这两个点y坐标相等,那么就直接求它们的x坐标的差值即可),如果不为0就输出0.

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>

typedef pair<int, int>PII;

bool cmp(PII a, PII b)
{
	if(a.second!=b.second)
		return a.second > b.second;
	return a.first > b.first;
}

int main()
{
	int n;
	cin >> n;
	vector<PII>v(3);
	while (n--)
	{
		for (int i = 0; i < 3; i++)
			cin >> v[i].first >> v[i].second;
		double len = 0;
		sort(v.begin(), v.end(), cmp);
		if (v[0].second == 0|| v[0].second != v[1].second)
		{
			cout << len << endl;
			continue;
		}
		if (v[0].second == v[1].second)
		{
			cout << abs(v[0].first-v[1].first) << endl;
		}
	}
		
	return 0;
}

C. Great Sequence

A sequence of positive integers is called great for a positive integer xx, if we can split it into pairs in such a way that in each pair the first number multiplied by xx is equal to the second number. More formally, a sequence a of size n is great for a positive integer xx, if n is even and there exists a permutation pp of size n, such that for each ii (1≤i≤n2) ap2i−1⋅x=ap2i.

Sam has a sequence a and a positive integer xx. Help him to make the sequence great: find the minimum possible number of positive integers that should be added to the sequence a to make it great for the number xx.

Input

Each test contains multiple test cases. The first line contains a single integer tt (1≤t≤200001≤t≤20000) — the number of test cases. Description of the test cases follows.

The first line of each test case contains two integers nn, xx (1≤n≤2⋅1051≤n≤2⋅105, 2≤x≤1062≤x≤106).

The next line contains n integers a1,a2,…,an (1≤ai≤10^9).

It is guaranteed that the sum of nn over all test cases does not exceed 2⋅1052⋅105.

Output

For each test case print a single integer — the minimum number of integers that can be added to the end of aa to make it a great sequence for the number xx.

Example

input

4
4 4
1 16 4 4
6 2
1 2 2 2 4 7
5 3
5 2 3 5 15
9 10
10 10 10 20 1 100 200 2000 3

output

0
2
3
3

Note

In the first test case, Sam got lucky and the sequence is already great for the number 44 because you can divide it into such pairs: (1,4)(1,4), (4,16)(4,16). Thus we can add 00 numbers.

In the second test case, you can add numbers 11 and 1414 to the sequence, then you can divide all 88 integers into such pairs: (1,2)(1,2), (1,2)(1,2), (2,4)(2,4), (7,14)(7,14). It is impossible to add less than 22 integers to fix the sequence.

这题意思是说,给你一个数组,再给你一个数x,然后看这个数组的每个数,有没有这么一对数,是前者x=后者的。如果整个数组都是这样的数对,这个数组就被称为伟大的数组,如果数组的数不够完成这些条件,那你可以插入数来让他变成伟大的数组。按样例来说 1 2 2 2 4 7,x是2。1 和2满足1 * 2=2,此时数组还剩2 2 4 7,2和4也满足这个条件,那就剩2 和7了,这俩不满足怎么办?那就插入一个1或4来和2组成数对(12=2或2 *2=4都是正确的),再插入一个14来和7配对,这样数组就是一个伟大的数组了,在此过程中我们插入了两个数,所以输出2。

我们用哈希表存数组每个数的出现情况,然后从小的数开始,看哈希表中有没有存这个数乘上x后的数,如果有,这个数的出现次数–,如果没有,计数器++(象征插入了一个数),最后输出计数器记录的值。

(昨晚听了dls的直播后知道了,unordered_map其实不好使,相比map来说慢了很多,这题一开始我用的是unordered_map,比赛时提交过了,但赛后系统测试的时候我的程序超时了,后来换成map后就过了,还有就是这题要开long long,不然有可能会炸掉,虽然题目的数组数据是在int范围内,但我们乘上x后可能会大于int范围,所以要开longlong,或者不用乘法,改为从大到小,看有没有整除x的)

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<map>

typedef long long ll;

int main()
{
	int n;
	cin >> n;
	while (n--)
	{
		map<ll, int>mymap;
		ll len, x;
		cin >> len >> x;
		vector<ll>v(len);
		for (int i = 0; i < len; i++)
			cin >> v[i];
		sort(v.begin(), v.end());
		int res = 0;
		for (auto i : v)mymap[i]++;
		for (auto i : v)
		{
			if (mymap[i] == 0)continue;
			mymap[i]--;
			if (mymap[i * x] != 0)mymap[i * x]--;
			else res++;
		}
		mymap.clear();
		cout << res << "\n";
	}

	return 0;
}

B. Power Walking

Sam is a kindergartener, and there are nn children in his group. He decided to create a team with some of his children to play “brawl:go 2”.

Sam has n power-ups, the ii-th has type ai. A child’s strength is equal to the number of different types among power-ups he has.

For a team of size kk, Sam will distribute all nn power-ups to kk children in such a way that each of the kk children receives at least one power-up, and each power-up is given to someone.

For each integer k from 1 to n, find the minimum sum of strengths of a team of kk children Sam can get.

Input

Each test contains multiple test cases. The first line contains a single integer tt (1≤t≤3⋅10^5) — the number of test cases. Description of the test cases follows.

The first line of each test case contains a single integer n (1≤n≤3⋅10^5).

The second line contains nn integers a1,a2,…,an (1≤ai≤10^9) — types of Sam’s power-ups.

It is guaranteed that the sum of nn over all test cases does not exceed 3⋅10^5.

Output

For every test case print nn integers.

The kk-th integer should be equal to the minimum sum of strengths of children in the team of size kk that Sam can get.

Example

input

2
3
1 1 2
6
5 1 2 2 2 4

output

2 2 3 
4 4 4 4 5 6 

Note

One of the ways to give power-ups to minimise the sum of strengths in the first test case:

  • k=1:{1,1,2}k=1:{1,1,2}
  • k=2:{1,1},{2}k=2:{1,1},{2}
  • k=3:{1},{1},{2}k=3:{1},{1},{2}

One of the ways to give power-ups to minimise the sum of strengths in the second test case:

  • k=1:{1,2,2,2,4,5}k=1:{1,2,2,2,4,5}
  • k=2:{2,2,2,4,5},{1}k=2:{2,2,2,4,5},{1}
  • k=3:{2,2,2,5},{1},{4}k=3:{2,2,2,5},{1},{4}
  • k=4:{2,2,2},{1},{4},{5}k=4:{2,2,2},{1},{4},{5}
  • k=5:{2,2},{1},{2},{4},{5}k=5:{2,2},{1},{2},{4},{5}
  • k=6:{1},{2},{2},{2},{4},{5}

这题也很简单,就是怎么把数分组,可以使得每组的力量和最小,而每组的力量由这个组有多少个不同的数决定。那么我们为了要力量和最小,可以经可能的控制一个组的不同的数最少,即把相同的数最后分组,先把单个的数分出去,比如1 2 2 3 3,如果我们先分了3出去,那就是{1 2 2 3}和{3}这样力量和是4,但如果我们把1分出去,就是{2 2 3 3}和{1},力量和是3.可以发现,因为单个的数不管放哪里都算一个能量,而多个相同的数只要在一组里就只算一个能量,但要是分出去了就不算一组里了,力量总和会+1,每有相同的数分开,能量就会+1.所以我们先计算总共有多少个单个的元素,,假设有m个,那我们前m个分组的时候,就把这些单个的分出去即可,这样从k=1到k=m这段上,能量总和不变,都是一开始不同元素的个数,输出完所有单个元素后,剩下的元素都是多个合在一起的,每次分一个出去能量都会+1,所以后半段的输出一直是在+1。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<map>

typedef long long ll;

int main()
{
	int n;
	cin >> n;
	while (n--)
	{
		map<ll, int>mymap;
		ll len, x;
		cin >> len >> x;
		vector<ll>v(len);
		for (int i = 0; i < len; i++)
			cin >> v[i];
		sort(v.begin(), v.end());
		int res = 0;
		for (auto i : v)mymap[i]++;
		for (auto i : v)
		{
			if (mymap[i] == 0)continue;
			mymap[i]--;
			if (mymap[i * x] != 0)mymap[i * x]--;
			else res++;
		}
		mymap.clear();
		cout << res << "\n";
	}

	return 0;
}

A. Doors and Keys

The knight is standing in front of a long and narrow hallway. A princess is waiting at the end of it.

In a hallway there are three doors: a red door, a green door and a blue door. The doors are placed one after another, however, possibly in a different order. To proceed to the next door, the knight must first open the door before.

Each door can be only opened with a key of the corresponding color. So three keys: a red key, a green key and a blue key — are also placed somewhere in the hallway. To open the door, the knight should first pick up the key of its color.

The knight has a map of the hallway. It can be transcribed as a string, consisting of six characters:

  • R, G, B — denoting red, green and blue doors, respectively;
  • r, g, b — denoting red, green and blue keys, respectively.

Each of these six characters appears in the string exactly once.

The knight is standing at the beginning of the hallway — on the left on the map.

Given a map of the hallway, determine if the knight can open all doors and meet the princess at the end of the hallway.

Input

The first line contains a single integer tt (1≤t≤720) — the number of testcases.

Each testcase consists of a single string. Each character is one of R, G, B (for the doors), r, g, b (for the keys), and each of them appears exactly once.

Output

For each testcase, print YES if the knight can open all doors. Otherwise, print NO.

Example

input

Copy

4
rgbBRG
RgbrBG
bBrRgG
rgRGBb

output

Copy

YES
NO
YES
NO

Note

In the first testcase, the knight first collects all keys, then opens all doors with them.

In the second testcase, there is a red door right in front of the knight, but he doesn’t have a key for it.

In the third testcase, the key to each door is in front of each respective door, so the knight collects the key and uses it immediately three times.

In the fourth testcase, the knight can’t open the blue door.

人话就是,小写字母是钥匙,大写字母是门,对应的字母是互相配对的,如果你在遇到门之前,没有获得对应的钥匙,说明你不能走到末尾,输出NO,如果能走到末尾就输出YES。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<string.h>
#include<string>
#include<unordered_map>
#include<math.h>
#include<queue>
#include<stack>

int main()
{
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		unordered_map<char, int>mymap;
		string str;
		cin >> str;
		bool flag = true;
		for (auto i : str)
		{
			if (i >= 97 && i <= 122)mymap[i]++;
			else
			{
				if (i == 'R')
				{
					if (mymap['r'] == 0)
					{
						cout << "NO" << endl;
						flag = false;
						break;
					}
				}
				else if (i == 'G')
				{
					if (mymap['g'] == 0)
					{
						cout << "NO" << endl;
						flag = false;
						break;
					}
				}
				else if (i == 'B')
				{
					if (mymap['b'] == 0)
					{
						cout << "NO" << endl;
						flag = false;
						break;
					}
				}
			}
		}
		if (flag)cout << "YES" << endl;
	}
	return 0;
}

B. Anti-Fibonacci Permutation

Let’s call a permutation pp of length n anti-Fibonacci if the condition pi−2+pi−1≠pi holds for all ii (3≤i≤n). Recall that the permutation is the array of length n which contains each integer from 11 to n exactly once.

Your task is for a given number nn print nn distinct anti-Fibonacci permutations of length nn.

Input

The first line contains a single integer tt (1≤t≤48) — the number of test cases.

The single line of each test case contains a single integer nn (3≤n≤50).

Output

For each test case, print nn lines. Each line should contain an anti-Fibonacci permutation of length nn. In each test case, you cannot print any permutation more than once.

If there are multiple answers, print any of them. It can be shown that it is always possible to find nn different anti-Fibonacci permutations of size nn under the constraints of the problem.

Example

input

Copy

2
4
3

output

Copy

4 1 3 2
1 2 4 3
3 4 1 2
2 4 1 3
3 2 1
1 3 2
3 1 2

就像题目说的,反斐波那契数列,一般的斐波那契数列是当前元素是前两个元素的和,这里是当前元素不是前两个元素的和,给我们一个数让我输出由1~n组成的n个不同的反斐波那契数列。

我们可以用dfs来搜,for循环枚举1n作为起点,然后第二个位置也一样是枚举1n,但不能和第一个元素相同,到了第三个元素之后,我们就要要求这个元素不能是前两个元素的和,满足条件就插入数组里送去找下一个位置的数,当我们得到的数列长度等于n时,输出这些数列。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<string.h>
#include<string>
#include<unordered_map>
#include<math.h>
#include<queue>
#include<stack>

unordered_map<int, int>mymap;
int res = 0;

void dfs(vector<int>& v,int n)
{
	if (res == n)return;
	if (v.size() == n)
	{
		res++;
		for (auto i : v)cout << i << " ";
		cout << endl;
		return;
	}
	int m = v.size();
	for (int i = 1; i <= n; i++)
	{
		if (mymap[i] != 1)
		{
			if (m < 2)
			{
				mymap[i]=1;
				v.push_back(i);
				dfs(v, n);
				v.pop_back();
				mymap[i] = 0;
			}
			else if (v[m - 1] + v[m - 2] != i)
			{
				mymap[i]=1;
				v.push_back(i);
				dfs(v, n);
				v.pop_back();
				mymap[i] = 0;
			}
		}
	}
}

int main()
{
	int num;
	cin >> num;
	while (num--)
	{
		int n;
		cin >> n;
		res = 0;
		if (n < 3)continue;
		for (int i = 1; i <= n; i++)
		{
			mymap[i] = 1;
			vector<int>v;
			v.push_back(i);
			dfs(v,n);
			mymap.clear();
		}
	}
	
	return 0;
}

Problem - C - Codeforces

You are given an array a1,a2,…,ana1,a2,…,an, consisting of nn integers. You are also given an integer value xx.

Let f(k)f(k) be the maximum sum of a contiguous subarray of aa after applying the following operation: add xx to the elements on exactly kk distinct positions. An empty subarray should also be considered, it has sum 00.

Note that the subarray doesn’t have to include all of the increased elements.

Calculate the maximum value of f(k)f(k) for all kk from 00 to nn independently.

Input

The first line contains a single integer t (1≤t≤50001≤t≤5000) — the number of testcases.

The first line of the testcase contains two integers n and xx (1≤n≤50001; 0≤x≤10^5) — the number of elements in the array and the value to add.

The second line contains n integers a1,a2,…,an (−105≤ai≤105).

The sum of n over all testcases doesn’t exceed 50005000.

Output

For each testcase, print n+1integers — the maximum value of f(k)f(k) for all k from 00 to n independently.

Example

input

3
4 2
4 1 3 2
3 5
-2 -7 -1
10 2
-6 -1 -2 4 -6 -1 -4 4 -5 -4

output

10 12 14 16 18
0 4 4 5
4 6 6 7 7 7 7 8 8 8 8

Note

In the first testcase, it doesn’t matter which elements you add xx to. The subarray with the maximum sum will always be the entire array. If you increase kk elements by xx, k⋅xk⋅x will be added to the sum.

In the second testcase:

  • For k=0k=0, the empty subarray is the best option.
  • For k=1k=1, it’s optimal to increase the element at position 33. The best sum becomes −1+5=4−1+5=4 for a subarray [3,3][3,3].
  • For k=2k=2, it’s optimal to increase the element at position 33 and any other element. The best sum is still 44 for a subarray [3,3][3,3].
  • For k=3k=3, you have to increase all elements. The best sum becomes (−2+5)+(−7+5)+(−1+5)=5(−2+5)+(−7+5)+(−1+5)=5 for a subarray [1,3][1,3].

这题是在经典dp问题:求最大连续子数组和的基础上扩展来的。这题就是说给我们一个数组和一个数x,让我们求数组加上了0~n个x后可以得到的最大连续子数组和。首先是贪心的想法,既然是可以加上一定数量的x,那我们肯定放在最大值能出现的地方,这里就需要我们枚举+滑动窗口了,假如可以放下2个x,我们就先开一个长度为2的滑动窗口,计算这个滑动窗口的总和+x*2,走到末尾后再把窗口大小+1从头开始继续算总和,当窗口大小等于数组长度后结束枚举,得到的最大值就是数组加入了2个x后可以得到的最大连续子数组和。由此类推3个x,就从长度为3的滑动窗口开始,0个x就从长度0开始。至于滑动窗口的和,我们可以用前缀和数组来进行优化。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<map>

typedef long long ll;

int main()
{
	int m;
	cin >> m;
	while (m--)
	{
		int n,x;
		
		cin >> n >> x;
		vector<int>s(n+1),v(n+1);
		for (int i = 1; i <= n; i++)
		{
			cin >> s[i];
			s[i] += s[i - 1];
			v[i] = -1e9;
		}
		v[0] = 0;
		if (s[1] == -2)
			cout << endl;
		for (int len = 1; len <= n; len++)
		{
			for (int i = 1; i + len - 1 <= n; i++)
			{
				int j = i + len - 1;
				v[len] = max(v[len], s[j] - s[i - 1]);
			}
		}
		for (int i = n - 1; i >= 0; i--)
			v[i] = max(v[i + 1], v[i]);
		int res = 0;
		for (int i = 0; i <= n; i++)
		{
			res = max(v[i] + i * x, res);
			cout << res << " ";
		}
		cout << endl;
	}

	return 0;
}

蓝桥杯——算法提高

算法提高 秘密行动

问题描述

小D接到一项任务,要求他爬到一座n层大厦的顶端与神秘人物会面。这座大厦有一个神奇的特点,每层的高度都不一样,同时,小D也拥有一项特殊能力,可以一次向上跳跃一层或两层,但是这项能力无法连续使用。已知向上1高度消耗的时间为1,跳跃不消耗时间。由于事态紧急,小D想知道他最少需要多少时间到达顶层。

输入格式

第一行包含一个整数n,代表楼的高度。

接下来n行每行一个整数ai,代表i层的楼层高度(ai <= 100)。

输出格式

输出1行,包含一个整数,表示所需的最短时间。

样例输入

5
3
5
1
8
4

样例输出

1

数据规模和约定

对20%的数据,n<=10
对40%的数据,n<=100
对60%的数据,n<=5000
对100%的数据,n<=10000

准备两个数组,一个dp[0] [N]:dp[0] [i]的意思是,在第i层的最后一步是爬,且到达这一层所花费的时间;一个dp[1] [N]:dp[1] [i]的意思是,在第i层的最后一层是跳,且到达这一层所花费的时间。初始化dp[1] [1]和dp[1] [1]为0,因为一开始就可以跳一层或跳两层,而跳不花时间,所以前两层我们就直接跳就行,dp[0] [1]初始化为f[1],因为第一层如果要爬花费时间肯定就是f[1](f是接收层高的数组)。然后开始推,每到一层,我们如果选择这一层爬,则可以在跳的那个数组(dp[1])里取前一层花费的时间加上这一层所需要的时间:dp[1] [i-1]+dp[0] [i],或是也可以假设上一层你爬了一层,这一层你接着爬,那就在爬的数组里取前一层花费的时间加上这一层所需要的时间:

dp[0] [i-1]+dp[0] [i].如果这一层你选择跳,则这一层所花时间等同于上一层跳所花费时间(跳不花时间,所以时间总数不变),也可以是等同于上上层所花时间(因为可以连跳两层)。最后从dp[0] [n]和dp[1] [n]中取最小值输出。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<map>

typedef long long ll;
const int N = 10010;
int dp[2][N], f[N];

int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> f[i];
	dp[0][1] = f[1];
	dp[1][1] = 0;
	dp[1][2] = 0;
	for (int i = 1; i <= n; i++)
	{
		dp[0][i] = min(dp[1][i - 1], dp[0][i - 1]) + f[i];
		if (i > 1)
			dp[1][i] = min(dp[0][i - 1], dp[0][i - 2]);
	}
	cout << min(dp[0][n], dp[1][n]);
	return 0;
}

步是爬,且到达这一层所花费的时间;一个dp[1] [N]:dp[1] [i]的意思是,在第i层的最后一层是跳,且到达这一层所花费的时间。初始化dp[1] [1]和dp[1] [1]为0,因为一开始就可以跳一层或跳两层,而跳不花时间,所以前两层我们就直接跳就行,dp[0] [1]初始化为f[1],因为第一层如果要爬花费时间肯定就是f[1](f是接收层高的数组)。然后开始推,每到一层,我们如果选择这一层爬,则可以在跳的那个数组(dp[1])里取前一层花费的时间加上这一层所需要的时间:dp[1] [i-1]+dp[0] [i],或是也可以假设上一层你爬了一层,这一层你接着爬,那就在爬的数组里取前一层花费的时间加上这一层所需要的时间:

dp[0] [i-1]+dp[0] [i].如果这一层你选择跳,则这一层所花时间等同于上一层跳所花费时间(跳不花时间,所以时间总数不变),也可以是等同于上上层所花时间(因为可以连跳两层)。最后从dp[0] [n]和dp[1] [n]中取最小值输出。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<map>

typedef long long ll;
const int N = 10010;
int dp[2][N], f[N];

int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++)
		cin >> f[i];
	dp[0][1] = f[1];
	dp[1][1] = 0;
	dp[1][2] = 0;
	for (int i = 1; i <= n; i++)
	{
		dp[0][i] = min(dp[1][i - 1], dp[0][i - 1]) + f[i];
		if (i > 1)
			dp[1][i] = min(dp[0][i - 1], dp[0][i - 2]);
	}
	cout << min(dp[0][n], dp[1][n]);
	return 0;
}