【22CSPJ普及组】真题解析

第一题:信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)icon-default.png?t=N7T8http://ybt.ssoier.cn:8088/problem_show.php?pid=2086

思路

一共有两种情况。第一种:如果 a == 1,不管 b 是多大,答案始终为一,直接输出即可

if(a == 1) {
	cout << 1 << endl;
	return 0;
}

第二种:a >= 2,int 类型能表示的最大数为 2^31 - 1,所以对于 a 来说,最多暴力计算 31 次答案就会超过 int 值,所以我们只需要暴力计算即可,无需优化

100分代码

#include<bits/stdc++.h>
using namespace std;

#define int long long

const int maxn = 1e9;

signed main() {
	int a, b;
	cin >> a >> b;
	
	if(a == 1) {
		cout << 1 << endl;
		return 0;
	}
	
	int ans = 1;
	for(int i = 1; i <= b; i++){
		ans *= a;
		if(ans > maxn){
			cout << -1 << endl;
			return 0; // 提前退出
		}
	}
	cout << ans << endl; 
	
	return 0;
}

第二题:信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)icon-default.png?t=N7T8http://ybt.ssoier.cn:8088/problem_show.php?pid=2087

思路

公式变形:n = p * q,   e * d = (p - 1) * (q - 1) + 1

可以得到:e * d = p * q - (p + q) + 2

因为:n = p * q,  所以: e * d = n - (p + q) + 2

那么:p + q = n - e * d + 2

又因为:n = p * q,  那么:q = n / p

那么:p + n / q = n - e * d + 2

由题,我们知道 p 和 q 都是 n 的因子,于是我们只需要枚举其中较小的一个因子 p 即可,另外一个因子即为 n / p

此方法枚举可拿60分

60分代码

#include<bits/stdc++.h>
using namespace std;

#define int long long

const int maxn = 1e9;

void solve() {
	int n, e, d;
	cin >> n >> e >> d;
	for(int i = 1; i <= sqrt(n); i++) {
		if(n % i == 0 && i + n / i == n - e * d + 2) {
			cout << i << " " << n / i << endl;
			return;
		}
	}
	cout << "NO" << endl;
}

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

由上面,p + n / p = n - e * d +2,其中,n e d 均为已知数

令 m = n - e * d + 2     则p + n / p = m

p * p - m * p + n =0,其中,n m 均为已知数

则题目变为解一元二次方程p * p - m * p + n =0

要求:delta >= 0 且解为整数

TIPS:输入输出使用 scanf, printf

100分代码

#include<bits/stdc++.h>
using namespace std;

#define int long long

const int maxn = 1e9;

void solve() {
	int n, e, d;
	scanf("%lld %lld %lld", &n, &e, &d);
	
	int m = n - e * d + 2;
	int delta = m * m - 4 * n;
	int res = sqrt(delta);
	
	if(delta < 0 || res * res != delta) {
		puts("NO");
		return ;
	}
	
	if((m + res) % 2 == 1) {
		puts("NO");
		return ;
	}
	printf("%lld %lld\n", (m - res) / 2, (m + res) / 2);
}

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

第三题:信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)icon-default.png?t=N7T8http://ybt.ssoier.cn:8088/problem_show.php?pid=2088

思路

第四题:

信息学奥赛一本通(C++版)在线评测系统 (ssoier.cn)icon-default.png?t=N7T8http://ybt.ssoier.cn:8088/problem_show.php?pid=2089

思路

 动态规划题

f[i][j] 表示以第 i 个点结尾,添加了 j 个点的最大长度

先将点集进行从小到大排序,第 i 个点可由第 i - 1 个点转移,假设两个点之间的距离为 len,则需要添加 len - 1 个点就可以满足题设条件

需要注意的是序列要满足横纵坐标均不递减

100分代码

#include<bits/stdc++.h>
using namespace std;

#define int long long
#define PII pair<int, int> 

const int maxn = 1e9;

int f[510][110];
vector<PII> res;
int n, k;

int get(PII a, PII b) {
	return abs(a.first - b.first) + abs(a.second - b.second);
}

int check(PII a, PII b) {
	return a.first >= b.first && a.second >= b.second;
}

void solve() {
	cin >> n >> k;
	
	res.push_back({0, 0}); 
	for(int i = 0; i < n; i++) {
		int a, b;
		cin >> a >> b;
		res.push_back({a, b});
	}
	
	sort(res.begin(), res.end());
	
	for(int i = 1; i <= n; i++){
		for(int j = 0; j <= k; j++) f[i][j] = j + 1;
	}
	
	int ans = -1;
	
	for(int i = 1; i <= n; i++){
		for(int j = 1; j < i; j++){
			int len = get(res[i], res[j]) - 1;
			if(!check(res[i], res[j])) continue; 
			if(len > k) continue;
			for(int g = len; g <= k; g++) {
				f[i][g] = max(f[i][g], f[j][g - len] + len + 1);
				ans = max(ans, f[i][g] + k - g);
			}
		}
	}
	cout << ans << endl;
}

signed main() {
	int _ = 1;// cin >> _;
	while(_--)  solve();
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值