比赛链接:

https://codeforces.com/gym/103447

B. Magical Subsequence

题意:

给定一个序列 \(A\),选择一个长为偶数的子序列 \(B\),使得 \(B_1 + B_2 = B_3 + B_4...\),问这个满足条件的子序列最长能是多少。

思路:

因为数字最大为 100,较小,考虑枚举两个数的总和。
定义 \(dp[i]\) 表示前 \(i\) 个数中能取到的子序列最大长度是多少。
现在枚举到的总和为 \(sum\),只要记录下每个值最近出现的位置,就可以知道 \(sum - A[i]\) 的位置,即这个位置的元素加上自己等于 \(sum\)
可以得到转移方程 \(dp[i] = max(dp[i], dp[pos[sum - A[i]] - 1] + 2\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int n;
	cin >> n;
	vector <int> a(n + 1);
	for (int i = 1; i <= n; i ++ )
		cin >> a[i];
	int ans = 0;
	for (int i = 2; i <= 200; i ++ ){
		vector <int> f(n + 1);
		map <int, int> pos;
		for (int j = 1; j <= n; j ++ ){
			f[j] = f[j - 1];
			if (pos.count(i - a[j])){
				f[j] = max(f[j], f[pos[i - a[j]] - 1] + 2);
			}
			pos[a[j]] = j;
			ans = max(ans, f[j]);
		}
	}
	cout << ans << "\n";
	return 0;
}

D. Math master

题意:

给定一个分数 \(p / q\),可以将 \(p, q\) 中都存在的数字删除掉,问能化到最简的分数是多少。

思路:

二进制枚举 \(p\) 最后剩下的是什么数,然后判断 \(q\) 删除 \(p\) 删除的数之后是不是原来的结果。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
vector <int> get(LL x){
	vector <int> a;
	while(x){
		a.push_back(x % 10);
		x /= 10;
	}
	return a;
}
void solve(){
	LL p, q;
	cin >> p >> q;
	LL fp = p, fq = q;
	auto A = get(p), B = get(q);
	LL g = __gcd(p, q);
	p /= g, q /= g;
	for (int i = 1; i < (1 << A.size()); i ++ ){
		LL t = 0;
		vector <int> cnt(10);
		for (int j = A.size() - 1; j >= 0; j -- ){  //从大到小选,因为要按顺序
			if ((i >> j) & 1) t = t * 10 + A[j];
			else cnt[A[j]] ++ ;
		}
		if (!t || t % p) continue;
		LL tmp = t / p * q;
		for (int j = 0; j < B.size(); j ++ ){
			if (tmp % 10 == B[j]) tmp /= 10;
			else cnt[B[j]] -- ;
		}
		if (tmp) continue;
		bool ok = true;
		for (int j = 0; j < 10; j ++ ){
			if (cnt[j]){
				ok = false;
				break;
			}
		}
		if (!ok) continue;
		if (t < fp){
			fp = t;
			fq = t / p * q;
		}
	}
	cout << fp << " " << fq << "\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int T = 1;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}

E. Power and Modulo

题意:

给定一个长为 \(n\) 的序列 \(A\)\(A_i = 2^{i - 1} \% M\),问 \(M\) 是否存在。

思路:

考虑 \(a_1\),如果是 0,那么 \(m\) = 0,然后逐一去判断后面所有数是不是都是 0。
如果是 1,那就往后去判断,当 \(a_{i - 1} * 2 != a_{i}\) 时,说明 \(m = a_{i - 1} * 2 - a_{i}\),然后判断整个序列是不是满足条件的。
如果是其他数,不可能,输出 -1 即可。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
void solve(){
	int n;
	cin >> n;
	vector <LL> a(n + 1);
	for (int i = 1; i <= n; i ++ )
		cin >> a[i];
	if (a[1] == 0){
		for (int i = 2; i <= n; i ++ ){
			if (a[i] != 0){
				cout << "-1\n";
				return;
			}
		}
		cout << "1\n";
	}
	else if (a[1] == 1){
		for (int i = 2; i <= n; i ++ ){
			if (a[i - 1] * 2 != a[i]){
				LL m = a[i - 1] * 2 - a[i];
				for (int j = 2; j <= n; j ++ ){
					if (a[j - 1] * 2 % m != a[j]){
						cout << "-1\n";
						return;
					}
				}
				cout << m << "\n";
				return;
			}
		}
		cout << "-1\n";
	}
	else {
		cout << "-1\n";
	}
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int T = 1;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}

I. Power and Zero

题意:

给定长为 \(n\) 的序列 \(A\),选择任意长度的序列 \(B\),使得 \(A_{B_1}, A_{B_2}, ..., A_{B_m}\) 分别减去 1,2,4...,\(2^m\),问最少几步可以使得序列 \(A\) 全为 0。

思路:

先记录每位上 1 的个数,第 \(i\) 位上的数量为 \(bit_i\),如果所有 \(bit_i < bit_{i + 1}\),那么最后答案就是 \(bit_0\)。因为位数高的会被删掉,且操作次数不会比低位的多。直接暴力就可以过。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
void solve(){
	int n;
	cin >> n;
	vector <int> a(n), bit(32);
	for (int i = 0; i < n; i ++ ){
		cin >> a[i];
		for (int j = 0; j < 31; j ++ )
			if ((a[i] >> j) & 1)
				bit[j] ++ ;
	}
	auto check = [&](){
		for (int i = 0; i < 30; i ++ ){
			if (bit[i] < bit[i + 1]){
				return false;
			}
		}
		return true;
	};
	while(!check()){
		for (int i = 30; i >= 1; i -- ){
			while (bit[i] > bit[i - 1]){
				bit[i] -- ;
				bit[i - 1] += 2;
			}
		}
	}
	cout << bit[0] << "\n";
}
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int T = 1;
	cin >> T;
	while(T -- ){
		solve();
	}
	return 0;
}

J. Local Minimum

题意:

计算同时是所在行和所在列的最小值的数的数量。

思路:

先判断行的最小值在哪,然后判断列的最小值在哪,比较是不是相同即可。

代码:

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1010;
LL a[N][N];
int main(){
	ios::sync_with_stdio(false);cin.tie(0);
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i ++ ){
		for (int j = 1; j <= m; j ++ ){
			cin >> a[i][j];
		}
	}
	set <int> s[1010];
	for (int i = 1; i <= n; i ++ ){
		LL mn = 1e9;
		for (int j = 1; j <= m; j ++ ){
			mn = min(mn, a[i][j]);
		}
		for (int j = 1; j <= m; j ++ ){
			if (mn == a[i][j]){
				s[j].insert(i);
			}
		}
	}
	LL ans = 0;
	for (int j = 1; j <= m; j ++ ){
		LL mn = 1e9;
		for (int i = 1; i <= n; i ++ ){
			mn = min(mn, a[i][j]);
		}
		for (int i = 1; i <= n; i ++ ){
			if (mn == a[i][j]){
				if (s[j].count(i)){
					ans ++ ;
				}
			}
		}
	}
	cout << ans << "\n";
	return 0;
}
posted on 2022-09-07 14:12  Hamine  阅读(343)  评论(0编辑  收藏  举报