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

比赛链接

正常枚举就行,从最后一位往前枚举,-1、-2、-3...这样

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;

typedef pair<int, int> PII;
typedef long long ll;

const int N = 1010;

int a[N];

void solve()
{
	int x, y, n;
	cin >> x >> y >> n;
	a[1] = x, a[n] = y;
	int res = 1;
	for(int i = n - 1; i >= 1; i --)
	{
		a[i] = a[i + 1] - res;
		res ++;
	}
	if(a[1] < x)
	{
		cout << -1 << endl;
		return;
	}
	a[1] = x;
	for(int i = 1; i <= n; i ++)cout << a[i] << ' ';
	cout << endl;
}

int main()
{
	IOS
	int _;
	cin >> _;
	while(_ --)
	{
		solve();
	}
	
	return 0;
}

 B

 第一个操作可以做到把所有在奇数位的字母任意排列以及把所有在偶数位的字母任意排列。

第二个操作,如果k是奇数时没有任何影响,只用第一种情况就能最优;如果k是偶数时,而且k又小于n,每次操作可以做到使区间内奇偶对调,进行两次操作[i,i+k-1],[i+1,i+k],这样只会发生两个数的下标奇偶性发生改变,然后这样就可以实现任意排序。

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;

typedef pair<int, int> PII;
typedef long long ll;

void solve()
{
	int n, k;
	cin >> n >> k;
	string A, B;
	string s;
	cin >> s;
	for(int i = 0; i < s.size(); i ++)
	{
		if(i % 2)B.push_back(s[i]);
		else A.push_back(s[i]);
	}
	sort(A.begin(), A.end());
	sort(B.begin(), B.end());
	sort(s.begin(), s.end());
	
	if(k % 2)
	{
		n = (n + 1) / 2;
		for(int i = 0; i < n; i ++)
		{
			if(i < A.size())cout << A[i];
			if(i < B.size())cout << B[i];
		}
	}
	else cout << s;
	cout << endl;
}

int main()
{
	IOS
	int _;
	cin >> _;
	while(_ --)
	{
		solve();
	}
	
	return 0;
}

C

 可以先把x变成2的i次方,在这个过程中用2的i次方减,一个数一定可以由若干2的i的方组成,x到2的i次方过程中减掉数的总和也一定可以由若干2的i次方组成。

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;

typedef pair<int, int> PII;
typedef long long ll;

ll a[50];
bool st[50];

void solve()
{
	vector<int> ans;
	int x;
	cin >> x;
	int l = 1, r = 32;
	while(l < r)
	{
		int mid = l + r + 1 >> 1;
		if(a[mid] <= x)l = mid;
		else r = mid - 1;
	}

	if(a[l] == x)
	{
		while(x != 1)
		{
			ans.push_back(x);
			x >>= 1;
		}
		ans.push_back(1);
		cout << ans.size() << endl;
		for(int i = 0; i < ans.size(); i ++)
		{
			cout << ans[i] << ' ';
		}
		cout << endl;
		return;
	}
	
	memset(st, false, sizeof st);
	while(x > a[l])
	{
		int tmp = x - a[l];
		int L = 1, R = 32;
		while(L < R)
		{
			int mid = L + R + 1 >> 1;
			if(a[mid] <= tmp)L = mid;
			else R = mid - 1;
		}
		
		for(int i = L; i >= 0; i --)
		{
			if(st[i])continue;
			if(x % a[i] == 0)
			{
				ans.push_back(x);
				x -= a[i];
				st[i] = true;
				break;
			}
		}
	}
	
	while(x != 1)
	{
		ans.push_back(x);
		x >>= 1;
	}
	ans.push_back(1);
	cout << ans.size() << endl;
	for(int i = 0; i < ans.size(); i ++)
	{
		cout << ans[i] << ' ';
	}
	cout << endl;
	return;
}

int main()
{
	IOS
	
	a[0] = 1;
	for(int i = 1; i <= 40; i ++)a[i] = a[i - 1] * 2;
	
	int _;
	cin >> _;
	while(_ --)
	{
		solve();
	}
	
	return 0;
}

D

 这题有点dp那味儿了,总的来说应该是前缀和,太久没写题手生了,写了一个多小时www

看那个公式画个图可以看出来它可以将一个点往下沿等腰三角形延伸,三角形区域内的点都要转换。

可以发现最上面那层有多少个1这一层肯定就要转换多少次,转换完后看第二层也类似,第二层有多少个需要转换的点这一层就要转换多少次,所以一定需要遍历一遍,往后以此类推。所以其实就是从第一层到最后一层遍历一遍所有点,遇到一个需要执行操作的点答案就加一。

现在复杂度已经到达n方了,我们需要想一个O(1)或者logn的算法来计算每个点需不需要转换,然后想到了前缀和,然后加一个额外的二维数组来统计每个点上方的等腰三角形区域内有多少个点被执行过操作。

然后前缀和转化成斜着的,同样是记录有多少个点被执行过操作。一个从左上到右下的斜前缀和数组,一个从右上到左下的斜前缀和数组。

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'

using namespace std;

typedef pair<int, int> PII;
typedef long long ll;

const int N = 3010;

int n;
char s[N][N];
int a[N][N], dg[N][N], udg[N][N];

void solve()
{
	cin >> n;
	
	for(int i = 0; i <= n + 1; i ++)
		for(int j = 0; j <= n + 1; j ++)
			a[i][j] = dg[i][j] = udg[i][j] = 0;
	
	for(int i = 1; i <= n; i ++)cin >> s[i] + 1;
	
	int ans = 0;
	for(int i = 1; i <= n; i ++)
	{
		for(int j = 1; j <= n; j ++)
		{
			a[i][j] = a[i - 1][j] + dg[i - 1][j - 1] + udg[i - 1][j + 1];
			int tmp = a[i][j] + s[i][j] - '0';
			if(tmp % 2)
			{
				ans ++;
				a[i][j] ++;
				dg[i][j] ++;
				udg[i][j] ++;
			}
			
			dg[i][j] += dg[i - 1][j - 1];
			udg[i][j] += udg[i - 1][j + 1];
		}
	}
	cout << ans << endl;
}

int main()
{
	IOS
	int _;
	cin >> _;
	while(_ --)
	{
		solve();
	}
	
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值