比赛链接:
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;
}