加载中...

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


前言

果然还是要刷题,而且要刷难题,好久不刷题找不到思考的感觉了,看到题目有无从下手的感觉。

第一题

题目: Problem - 1631A - Codeforces

题意:

给两个数组a和b,可以任意交换ai和bi,求最后两个数组各自的最大值乘积。

输入格式

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

每个样例第一行是一个整数,代表数组中的元素个数。

每个样例的第二行和第三行均是n个整数。

数据范围

1 ≤ t ≤ 100

1 ≤ n ≤ 100

1 ≤ ai ≤ 10000,1 ≤ bi ≤ 10000

输出格式

输出一个整数。

输入样例:

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

输出样例:

18
9
2

思路:

  • 无论怎么交换,两个数组中所有元素的最大值是无法避免被乘的,所以我们可以先确定总体的最大值,然后再依次遍历两个数组,看是否有两个同一位置的元素大于与总体最大值同一位置的元素,尽量将总体最大值对应位置的另一个数的值变小

代码:

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 10010;

int n;
pair<int, int>p[N];

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

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		cin >> n;
		int x=0, y=0;
		for (int i = 1; i <= n; ++i)
		{
			cin >> p[i].first;
			x = max(x, p[i].first);
		}
		for (int i = 1; i <= n; ++i)
		{
			cin >> p[i].second;
			y = max(y, p[i].second);
		}

		if (x > y) sort(p + 1, p + n + 1);
		else sort(p + 1, p + n + 1, cmp1);

		int m1,m2;
		if (p[n].first > p[n].second)m1 = p[n].first,m2=p[n].second;
		else m1 = p[n].second,m2=p[n].first;

		for (int i = n - 1; i >= 1; --i)
		{
			if (p[i].first > m2 && p[i].second > m2)
				m2 = min(p[i].first, p[i].second);
		}

		cout << m1 * m2 << endl;
	}

	return 0;
}

第二题

题目: Problem - 1631B - Codeforces

题意:

给定我们一个数组,每次可以选择两个数字l和k,然后将数组的[l, l+k-1]依次赋值为[l+k,l+2k-1],要让数组中所有元素均相同最少需要几步。

输入格式

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

每个样例第一行是一个整数n,代表数列有n个整数。

每个样例第二行是n个整数,代表整个 数列。

输出格式

一个整数,表示第几个字符串。

数据范围

1 ≤ t ≤ 2×104

1 ≤ n ≤ 2×105

1 ≤ ai ≤ n

输入样例:

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

输出样例:

0
1
1
2
0

思路:

  • 因为我们在将区间赋值时,只能从后向前赋值,所以如果整个数列所有元素均相同,那么值一定等于最后一个数。
  • 所以我们从倒数第二个数出发,每次遇到与最后一个数不同的数,就将已经遍历的数组赋值到前面。

代码:

#include<iostream>
#include<cstring>
#include<algorithm>
 
using namespace std;
 
const int N = 200010;
 
int n;
int a[N];
 
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		cin >> n;
		for (int i = 1; i <= n; ++i)cin >> a[i];
 
		int cnt = 0;
		for (int i = n-1; i >= 1;--i)
		{
			if (a[i] != a[n])
			{
				cnt++;
				i = i - (n - i) + 1;
			}
		}
		cout << cnt << endl;
	}
	return 0;
}

第三题-赛后补题

题目: Problem - 1631C - Codeforces

题意:

给我们两个整数n和k,n表示我们有0到n-1个整数,要求我们找到 n/2 对整数,使每一对数进行与操作后的和等于k。

输入格式

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

每个样例只有两个整数n和k。

输出格式

每个样例如果能找到符合条件的 n/2 对整数,则每行输出一对,共 n/2 行。否则输出 -1

数据范围

1 ≤ t ≤ 400

4 ≤ n ≤ 216, 0 ≤ k ≤ n−1

输入样例:

4
4 0
4 1
4 2
4 3

输出样例:

0 3
1 2
0 2
1 3
0 1
2 3
-1

思路:

  • 分类讨论。
  • 第一种情况,当 k==0 时,我们可以从 [0, n-1] 区间两侧开始向内一一配对。每对与操作后和为0。
  • 第二种情况,当k不为0时:
    • 如果 k<n-1 ,那么我们显然可以将k与 n-1 放到一组,这时与的操作结果为k,我们只需要将剩下的数配对后与操作之和结果为0即可,我们会发现 k<n-1k==0 实际上只有两组不同,涉及到 {0, n-1, k, n-k-1} 四个数,而去除k和 n-1 后,0和 n-k-1 进行与操作结果同样为0,那么剩下的数和 k==0 进行相同操作即可。
    • 如果 k==n-1 ,我们需要凑出k,那么我们可以先用 n-1n-2 与操作得到 n-2 ,然后用 n-3 和1进行与操作得到1,然后将0和2配对得到0,这时我们会发现 n-2+1=k ,之后剩下的数和 k==0 时操作相同。
  • 注意需要特判当n==4&&k==3时这种情况,因为:n-1和n-2配对,n-3和0配对,还剩一个1无法实现

代码:

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

const int N = 200010;

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n, k;
		cin >> n >> k;
		//当n==4&&k==3时,n-1和n-2配对,n-3和0配对,还剩一个1无法实现
		if (n == 4 && k == 3)cout << "-1" << endl;
		else if (k == 0)
			for (int i = 0; i < n / 2; ++i) cout << i << " " << n - 1 - i << endl;
		else if (k < n - 1)
		{
			//让k与n-1与操作,结果还是k
			cout << k << " " << n - 1 << endl;
			//0和n-k-1本来应该分别与n-1和k配对
			cout << 0 << " " << n - k - 1 << endl;
			for (int i = 0; i < n / 2; ++i)
			{
				if (i == k || i == 0 || i == n - k - 1 || i == n - 1)continue;
				else cout << i << " " << n - 1 - i << endl;
			}
		}
		else
		{
			cout << n - 1 << " " << n - 2 << endl;//n-2
			cout << n - 3 << " " << 1 << endl;//1  n是偶数,所以n-3是奇数
			cout << 0 << " " << 2 << endl;//0
			for (int i = 3; i < n / 2; ++i)cout << i << " " << n - i - 1 << endl;
		}
	}
	return 0;
}

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