Harbour.Space Scholarship Contest 2023-2024 (Div. 1 + Div. 2) A~D

A. Increasing and Decreasing

题意:给出x, y, n,构造长度为n的递增数列使得 a1 = x, an = y, 并且相邻元素的差值递减。如果不能构造输出-1。

思路:如果能够构造出来,那么y - x的值应该大于 1 到 n - 1 的累加。构造时从y开始,依次向前 -1 -2 -3....即可。

AC代码

#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#define int long long
using namespace std;
const int N = 100010;
const int M = 200020;
int a[N];
void solve()
{
	int x, y, n;
	cin >> x >> y >> n;
	a[1] = x, a[n] = y;
	int res = 0;
	for (int i = 1; i < n; i++)res += i;
	if (y - x < res)
	{
		cout << -1 << endl;
		return;
	}
	for (int i = n - 1; i > 1; i--)
	{
		a[i] = a[i + 1] - (n - i);
	}
	
		for (int i = 1; i <= n; i++)cout << a[i] << " ";
		cout << endl;
	
}
signed main()
{
	int t;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

B. Swap and Reverse

题意:给定一个长度为n的字符串,可以进行两种操作:

1.交换 a_{i} 和 a_{i + 2}

2.翻转 [i, i + k - 1] 区间的字符。

输出能够构造出的字典序最小的字符串。

思路:第一种操作只可以对奇偶性相同的字符进行操作,当 k 为奇数时,第二种操作同样只能对奇偶性相同的字符进行操作,当k为偶数时,第二种操作就可以改变字符位置的奇偶性。所以当 k 为偶数时,直接排序字符输出即可,当 k 为奇数时,对奇数序列和偶数序列分别排序输出。

AC代码

#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#define int long long
using namespace std;
const int N = 100010;
const int M = 200020;
int a[N];
struct Node
{
	char c;
	int via;
}tr[N];
void solve()
{
	int n, k;
	cin >> n >> k;
	string arr;
	cin >> arr;
	if (k % 2 == 0)
	{
		sort(arr.begin(), arr.end());
		cout << arr << endl;
		return;
	}
	else {
		string ji, ou;
		for (int i = 0; i < n; i++)
		{
			if (i % 2 == 0)ji += arr[i];
			else ou += arr[i];
		}
		sort(ji.begin(), ji.end());
		sort(ou.begin(), ou.end());
		int cntji = 0, cntou = 0;
		for (int i = 0; i < n; i++)
		{
			if (i % 2 == 0)
			{
				cout << ji[cntji++];
			}
			else cout << ou[cntou++];
		}
	}
	cout << endl;
}
signed main()
{
	int t;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

C. Divisor Chain

题意:给定一个数 x,每次只能减去它的除数,并且同一个除数最多用两次,直到减为一,输出每次变换后的序列。

思路:如果这个数是 2 的次幂,那么它只需要依次除 2 即可,例如 8 的输出为 8 4 2 1。如果不是 2 的次幂,可以考虑将他变为 2 的次幂,只需要减去二进制中除了第一位以外的 1 即可。例如 14 的二进制为 1110 ,那么我们只需依次减去 10 100 即可,(一个二进制数必定能整除最低位的1)。那14 的输出即为 14 12(-2) 8(-4) 4 2 1。

AC代码 

#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#define int long long
using namespace std;
const int N = 100010;
const int M = 200020;
int two[N];
int find(int x)
{
	for (int i = 0; i < 60; i++)
	{
		if (x == two[i])return 1;
	}
	return 0;
}
void solve()
{
	int n;
	cin >> n;
	if (n == 2)
	{
		cout << 2 << endl;
		cout << 2 << " " << 1 << endl;
		return;
	}
	vector<int> ans;
	ans.push_back(n);
	int cnt = n;
	while (cnt != 1)
	{
		if (find(cnt))break;
		int a = 0;
		while (!(cnt >> a & 1))a++;
		cnt -= two[a];
		ans.push_back(cnt);
	}
	while (cnt != 1)
	{
		cnt /= 2;
		ans.push_back(cnt);
	}
	cout << ans.size() << endl;
	for (auto x : ans)cout << x << " ";
	cout << endl;
}
signed main()
{
	two[0] = 1;
	for (int i = 1; i < 60; i++)
	{
		two[i] = two[i - 1] * 2;
	}
	int t;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

D. Matrix Cascade

题意:给定一个n*n的矩阵,矩阵中的元素不是 0 就是 1,选定一个位置例如(i, j),那么以这个点为顶点做两条线,斜率为 1 和 -1,两条斜线以下的区域中的元素会翻转,问将矩阵全部变为0所需的最小操作。

思路:对于一个点(i, j),这个点以下的点是影响不到它的,所以对于(i, j),只考虑这个点以上的点即可。如果一个点进行了奇数次操作,那这个点会翻转,如果是偶数次就没有变化。所以遍历每一个点,如果这个点经过所有变化后仍为 1 ,那么此时只能改变这个点的值,答案就加一。至于如何记录上面点对下面点的影响, 我们可以维护两个前缀和数组,分别表示斜率为 1 和 -1。那么对于任一个点,只用考虑上方,左上方和右上方点的影响即可。

思路参考:http://t.csdn.cn/sHHfg

AC代码

#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#define int long long
using namespace std;
const int N = 3010;
int a[N][N], sk[N][N], usk[N][N];
int cnt[N][N];
void solve()
{
	int n;
	cin >> n;

	for (int i = 0; i <= n + 1; i++)
	{
		for (int j = 0; j <= n + 1; j++)
		{
			cnt[i][j] = 0;
			sk[i][j] = 0;
			usk[i][j] = 0;
		}
	}

	for (int i = 1; i <= n; i++)
	{
		string arr;
		cin >> arr;
		for (int j = 1; j <= n; j++)
		{
			a[i][j] = arr[j - 1] - '0';
		}
	}
		

	int ans = 0;
	for(int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
		{
			cnt[i][j] += cnt[i - 1][j] + sk[i - 1][j + 1] + usk[i - 1][j - 1];
			int res = cnt[i][j] + a[i][j];

			if (res % 2)
			{
				ans++;
				cnt[i][j]++;
				sk[i][j]++;
				usk[i][j]++;
			}

			sk[i][j] += sk[i - 1][j + 1];
			usk[i][j] += usk[i - 1][j - 1];
		}

	cout << ans << endl;
}
signed main()
{
	int t;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值