CF补题 991-Div.3-20241210
Dashboard - Codeforces Round 991 (Div. 3) - Codeforces
A:
题目大意:给出 \(n\) 个字符串,求前多少个字符串的大小之和小于 \(m\)
#include <iostream>
#include <string>
using namespace std;string a[52];int main()
{int T;cin >> T;while (T--){int n, m;int flag = 0;cin >> n >> m;for (int i = 1; i <= n; i++)cin >> a[i];//读入所有字符串for (int i = 1; i <= n; i++) {if (m >= a[i].size()) {//如果能当前的m大于当前遍历的字符串的大小flag++;m -= a[i].size();//就把他减去}else break;//否则,退出}cout << flag << endl;//输出前flag个for (int i = 1; i <= n; i++) a[i].clear();//初始化}return 0;
}
签到题数据有点坑,调了很久
B:
题目大意:给定一个序列,每次选择其中一个元素,对他的左右两个元素分别做加减 \(1\) 操作,求能否使序列所有元素都变为相同
#include <string>
using namespace std;int main()
{int T;cin >> T;while (T--){int n,a;int flag = 0;long long oddsum = 0, evesum = 0;scanf("%d", &n);for (int i = 1; i <= n; i++) {scanf("%d", &a);if (i % 2) oddsum += a;else evesum += a;}long long oddcnt = n % 2 == 0 ? n / 2 : n / 2 + 1, evecnt = n / 2;if (oddsum % oddcnt != 0 || evesum % evecnt != 0 || (oddsum / oddcnt)!= (evesum / evecnt))cout<<"NO"<<endl;else cout<<"YES"<<endl;}return 0;
}
属于是不开 long long
见祖宗,题目只给出了 \(sum(n)<2e5\) 没说 \(sum(a)\) 的范围
所以调了很多次,发现需要开 long long
记录元素和
因为我们更改元素的值时,是对相同奇偶位的元素进行更改,所以我们需要保证 奇数位上的数 和 偶数位上的数
他们各自的和都能被 奇数位个数 和 偶数位个数 整除,且还要满足他们各自的平均值相等,才能使序列所有元素都变为相同
C:
题目大意:给出一个数,每次可以对它任意一个位置上的数进行平方操作(得到的数必须小于10),求能否得到能一个被 \(9\) 整除的数
#include <string>
#include <iostream>
#include <vector>
using namespace std;bool check(vector<int> a) {int sum = 0, mem2 = 0, mem3 = 0;for (int i = 0; i < a.size(); i++) {if (a[i] == 2) mem2++;if (a[i] == 3) mem3++;sum += a[i];}if (mem3 >= 2 && sum % 9 == 0) return 1;if (mem2 >= 8) return 1;for (int i = 0; i <= mem2; i++)for (int j = 0; j <= mem3; j++)if ((sum + i * 2 + j * 6) % 9 == 0) return 1;return 0;
}int main()
{int T;cin >> T;while (T--) {string s;vector<int> a;cin >> s;for (int i = 0; i < s.size(); i++)a.push_back(s[i] - '0');if (check(a)) cout << "YES" << endl;else cout << "NO" << endl;}return 0;
}
题目给出的数,它的位数小于 \(10^5\) 即最多有 \(100000\) 位,远远大于 long long
的范围
使用 string
读入数据,把每一位取出来存进 vector
关于一个数能否被 \(9\) 整除,有定理如下:
能被 \(9\) 整除的数,各个数位上的数字和能被 \(9\) 整除,那么这个数能被 \(9\) 整除
所以在 check
函数内取出每个位上的数,进行判断
根据题意,我们只能对 \(1,2,3\) 进行平方操作,而且 \(1\) 的平方仍然为 \(1\) ,只需要记录 \(2,3\) 的数量
由于 \(mod\ 9\) 的余数只有 \(\{1,2,3,4,5,6,7,8\}\) ,存在以下情况:
\(1+2*3=9,\ 2+2*8=18,\ 3+2*2=9,\ 4+2*7=18\)
\(5+2*2=9,\ 6+2*6=18,\ 7+2=9,\ 8+2*5=18\)
每次对 \(2\) 进行平方是,对 sum
的贡献为 +2
,所以的余数都能由最多 \(8\) 个 \(2\) 所组合成为能被整除的数
故当 \(2\) 的数量大于等于 \(8\) 时,一定有解
由于 \(3\) 的平方对 sum
的贡献为 +3
,且 \(3\) 次 +3
也会被 \(9\) 整除,所以有:
\(3\) 的数量大于等于 \(2\) 时, 若 sum
已是 \(3\) 的倍数,则一定能凑出解
剩下的情况只有 \(2,3\) 的数量分别小于 \(8,2\) ,直接枚举出所有情况再判断是否有解
D:
题目大意:给出一个数字串,每次可以选择其中非 \(0\) 和最左边的数字,将它减去 \(1\) 和左边的数字交换,求最大序字符串
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;int T;
string s;int main()
{cin >> T;while (T--) {cin >> s;for (int i = 0; i < s.size(); i++) {int mmax = i, mempos = 0;for (int j = i; j < min(i + 10, (int)s.size()); j++) {if (s[mmax]-mempos < s[j] - j + i) {mmax = j;mempos = j - i;}}for (int j = mmax; j > i; j--) {s[j]--;swap(s[j], s[j - 1]);}}cout << s << endl;}return 0;
}
贪心的思想,由于我们最多只能把一个数减到 \(0\) ,所以对一个数,枚举它之后的所有能交换的数的枚举次数,最多不超过 \(9\) 次
数据范围满足时间限制,应该能够过
首先读入这个数字串,从最高位开始,对每一位都向后枚举 min(i + 10, (int)s.size())
,记录枚举的过程中能让这个数交换后变得最大的 mmax
下标,以及离当前数字的距离 mempos
枚举完后,从 mmax
下标开始向前枚举,每次执行 -1
和 swap
操作
最后输出 s
得到全局最优解