加载中...

SDTBU-ACM集训队暑期集训---个人赛 12


前言

有思路就能AC的感觉太爽了。

第一题

题目: Math Problem

题意:

给我们n个区间,找到一个最短的区间,将所有的区间连在一起(换句话说就是找到的区间和所有的区间都有共同的点)。所找到的区间长度可以为0,即只有一个点。

输入格式

输入包含多个样例,第一行是一个整数t,表示有t个样例。

每个样例第一行是一个整数n,表示有n个区间。

每个样例第2到n+1行每行是两个整数l和r,表示区间的左右端点。

输出格式

输出一个整数,表示区间的长度。

数据范围

1 ≤ t ≤ 100

1 ≤ n ≤ 105

1 ≤ li ≤ ri ≤ 109

数据保证所有的n总和不超过1×105

输入样例:

4
3
4 5
5 9
7 7
5
11 19
4 17
16 16
3 12
14 17
1
1 10
1
1 1

输出样例:

2
4
0
0

思路:

  • 贪心。每次遇到贪心我都不知道是怎么做出来的,迷迷糊糊的,完全凭感觉走,感觉这么做能AC于是就AC了。
  • 将所有区间按右端点(即结束端点)升序排序。
  • 将第一个区间的右端点记为max_r,从第二个区间开始遍历,每当第i个区间的左端点大于当前的max_r时,就更新max_r。
  • 最后输出 max_r - p[1].second
  • 贪心题做的越多越佩服yxc,讲贪心题都要当场证明。会做题只能说明很牛,但是和我有什么关系呢,自己会还能教会别人的才是大佬。

代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 1e5 + 10;

int n;

bool cmp(pair<int, int>a, pair<int, int>b)
{
	return a.second < b.second;
}

int main()
{
	int t;
	cin >> t;

	while (t--)
	{
		cin >> n;
		pair<int, int>p[N];
		for (int i = 1; i <= n; ++i)
		{
			cin >> p[i].first >> p[i].second;
		}

		sort(p + 1, p + n + 1, cmp);

		int l = p[1].second;
		for (int i = 2; i <= n; ++i)
		{
			l = max(l, p[i].first);
		}

		cout << l - p[1].second << endl;
	}
	return 0;
}

第二题

题目: Box

题意:

给我们一个长度为n的序列,要求我们根据给定的序列构建一个长度为n的序列,由数字1n构成,不能有重复的数字。所构建的序列前i个数的最大值要等于给定数列的第i个数qi~。如果所给数列无法构造输出-1。

输入格式

输入包含多个样例,第一行是一个整数t,表示有t个样例。

每个样例第一行是一个整数n,表示给定的数列有n个数。

每个样例第二行是n个整数。

输出格式

如果能够构造出来,将所构造的数列输出,每个数字用空格间隔,否则输出-1。每个样例占一行。

数据范围

1 ≤ t ≤ 104

1 ≤ n ≤ 105

1 ≤ qi ≤ n

保证所给的样例是非下降数列,并且所有的n总和不超过1×105

输入样例:

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

输出样例:

1 3 4 5 2 
-1
2 1 
1 

思路:

  • 用数组a存给定的数列,数组b存构建的数列,数组p记录1~n哪些数被加入到b数组中。
  • 首先由于我们构建的数列不能有重复的数字,并且所给定的数列是非下降的,那么就可以得出,如果 a[i]<i 一定是无解的,例如给定的数列第3个数是2,我们是无法构建出前三个数中最大值是2的数列的。而只要满足对于任意的i,都有 a[i]>=i ,那么一定有解。
  • 我们可以将所要构建的数组视为一个集合b,集合b初始时为空,遍历所给定的数列a来向集合b中添加数字。
  • 我们用数组p来记录1~n中哪些数已经被我们加入到所构建的数组b中。当我们遍历所给数列a时,如果a[i]还没有被添加到b中,那么就直接加入,否则将当前未被添加的最小的数加入到集合b中。
  • 因为如果是第一次遇到a[i],说明a[i]是大于当前b集合中 i-1 个数的,所以我们直接将a[i]加入到b集合中。如果此时a[i]已经被加入,说明a[i]小于集合b中的某些数,那么我们直接将当前未放入的最小的数加入集合b中就好了。
  • 这里就有一个问题,怎么找到当前最小的数,如果每次都遍历p数组,最坏情况下时间复杂度是O(n2)的,而n的范围最大是105,也就是100亿的级别,一定会超时。我们可以用一个变量j来记录当前的最小值,每次加入集合b中一个数就判断一下j是否已经被加入集合,是的话就让j=j+1,这样时间复杂度就是O(n),只用遍历一遍就可以。

代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<cstring>

using namespace std;

const int N = 1e5 + 10;

int a[N],b[N];//a存给定的数列,b存构建的数列
bool p[N];//p[i]表示数字i是否已经加入到所构建的数列中

int main()
{
	int t;
	scanf("%d", &t);

	while (t--)
	{
		int n;
		scanf("%d", &n);
		int flag = 0;
		for (int i = 1; i <= n; ++i)p[i] = 0;
		for (int i = 1; i <= n; ++i)
		{
			scanf("%d", &a[i]);
			if (a[i] < i)flag = 1;
		}

		if (flag)
		{
			cout << -1 << endl;
			continue;
		}

		flag = 0;
		int j = 1;
		for (int i = 1; i <= n; ++i)
		{
			if (p[a[i]]==0)
			{
				b[i] = a[i];
				p[a[i]] = 1;
			}
			else
			{
				b[i] = j;
				p[j] = 1;
			}
			while (p[j])j++;
		}

		for (int i = 1; i <= n; ++i)printf("%d ", b[i]);
		printf("\n");
	}
	return 0;
}

第四题

题目: Optimal Subsequences (Easy Version)

题意:

给我们一个长度为n的数列,然后是m次询问,每次询问给两个数k和pos,要求我们在给定的数列中找到长度是k的子序列中找到所有元素和最大的子序列,然后在找到的子序列中找到字典序最小的序列,然后在字典序最小的序列中找到第pos个数并输出。

输入格式

输入第一行是一个整数n。

输入第二行是n个整数a1 ~ an,表示整个数列。

第三行是一个整数m。

接下来第4到m+4行是m次询问,每次询问给两个整数k和pos。

输出格式

输出一个整数。

数据范围

1 ≤ n ≤ 100

1 ≤ ai ≤ 109

1 ≤ m ≤ 100

1 ≤ k ≤ n, 1 ≤ posj ≤ kj

输入样例:

3
10 20 10
6
1 1
2 1
2 2
3 1
3 2
3 3

输出样例:

20
10
20
10
20
10

思路:

  • 因为所给的m和n范围都很小,所以我们可以提前将长度1~n的所有子序列中值最大,且字典序最小的序列存下来,每次询问时直接输出就好了。

代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<cstring>

using namespace std;

const int N = 1e2 + 10;

bool cmp(int a, int b)
{
	return a > b;
}

int a[N];
int b[N][N];

int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; ++i)scanf("%d", &a[i]);

	int c[N];
	for (int i = 1; i <= n; ++i)c[i] = a[i];
	sort(c + 1, c + n + 1,cmp);

	for (int i = n; i >=1 ; --i)
	{
		int k = 1;
		for (int j = 1; j <= n && k <= i; ++j)
		{
			if(a[j])b[i][k++] = a[j];
		}

		for (int j = n; j >= 1; --j)
		{
			if (a[j] == c[i])
			{
				a[j] = 0;
				break;
			}
		}
	}
	
	int m, k, p;
	cin >> m;
	while (m--)
	{
		cin >> k >> p;
		cout << b[k][p] << endl;
	}
	return 0;
}

文章作者: 心意
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 心意 !
评论
  目录