Codeforces Round #828 (Div. 3) 这场难度在div3中感觉相对较高,题的质量是不错的,有学习价值。
A Number Replacement
思路:注意到a[i]=a[j]时必须有s[i]=s[j],而数据规模很小。因此O(n^2)暴搜解决。
代码如下:
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n;
cin >> n;
int a[100];
char b[100];
for (int i = 0; i < n; i++)
cin >> a[i];
cin >> b;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (a[i] != a[j])
continue;
if (b[i] != b[j]) {
cout << "NO" << endl;
return;
}
}
}
cout << "YES" << endl;
return;
}
int main() {
int n;
cin >> n;
while (n--) {
solve();
}
return 0;
}
B Even-Odd Increments
思路:将偶数和奇数分开考虑,分别储存偶数之和、偶数个数、奇数之和、奇数个数。对于每一次操作,如果新增的x是偶数,则原奇偶性不变,如果新增的x是奇数,则改变奇偶性。
代码如下:
#include <bits/stdc++.h>
using namespace std;
void solve() {
long long n, q, op, tp;
long long sum1 = 0, sum2 = 0, cou1 = 0, cou2 = 0;
cin >> n >> q;
for (int i = 0; i < n; i++) {
cin >> tp;
if (tp % 2) {
sum1 += tp;
cou1++;
} else {
sum2 += tp;
cou2++;
}
}
for (int i = 0; i < q; i++) {
cin >> op >> tp;
if (op == 0) {
sum2 += cou2 * tp;
if (tp % 2) {
sum1 += sum2;
cou1 += cou2;
sum2 = 0;
cou2 = 0;
}
} else {
sum1 += cou1 * tp;
if (tp % 2) {
sum2 += sum1;
cou2 += cou1;
sum1 = 0;
cou1 = 0;
}
}
cout << sum1 + sum2 << endl;
}
return;
}
int main() {
int n;
cin >> n;
while (n--) {
solve();
}
return 0;
}
C Traffic Light
思路:需要找到对应颜色和后面第一个Green之间距离差值的最大值。注意到红绿灯是循环的,因此O(n)扫两个循环节即可。
代码如下:
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n;
char c;
cin >> n >> c;
string s;
cin >> s;
if (c == 'g') {
cout << 0 << endl;
return;
}
int maxm = 0;
int flag = 0, bj;
for (int i = 0; i < 2 * n; i++) {
int q = i % n;
if (flag == 0 && s[q] == c) {
flag = 1;
bj = i;
continue;
}
if (flag == 1 && s[q] == 'g') {
flag = 0;
if (i - bj > maxm)
maxm = i - bj;
}
}
cout << maxm << endl;
return;
}
int main() {
int n;
cin >> n;
while (n--) {
solve();
}
return 0;
}
D Divisibility by 2^n
思路:此题因注意到输入的数据是没用的,有用的仅仅是输入数据中有多少个2因子。先将2因子的数量统计出来,然后判断我们缺少了多少个2因子。
那缺少的2因子需要多少步操作得到呢?注意到,对于每个n=2^k的倍数,都具有k个2因子。因此我们统计含i个2因子的数的数量存在数组eys[i]中,然后模拟具体情况解决。
代码如下:
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n, tp, eyz = 0;
int eys[100];
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &tp);
if (eyz >= n)
continue;
while (tp % 2 == 0) {
tp /= 2;
eyz++;
}
}
if (eyz >= n) {
cout << 0 << endl;
return;
}
int cz = n - eyz, sum = 0, cou = 0;
int j = 1;
for (int i = 2; i <= n; i *= 2) {
eys[j] = n / i;
j++;
}
for (int p = 1; p < j - 1; p++) {
eys[p] -= eys[p + 1];
}
for (int p = j - 1; p >= 1; p--) {
if (sum + eys[p]*p < cz) {
sum += eys[p] * p;
cou += eys[p];
continue;
} else {
cou += (cz - sum) / p;
if ((cz - sum) % p != 0)
cou++;
cout << cou << endl;
return;
}
}
cout << -1 << endl;
return;
}
int main() {
int n;
cin >> n;
while (n--) {
solve();
}
return 0;
}
E1 - Divisible Numbers(easy version)
思路:将x从a+1到c遍历一遍,对于每个x,我们只需要找出是否存在一个[b+1,d]中的y满足x*y整除a*b。而x*y整除a*b可以化为y整除a*b/gcd(a*b,x)。
代码如下:
#include <bits/stdc++.h>
using namespace std;
void solve() {
long long a, b, c, d;
cin >> a >> b >> c >> d;
for (long long i = a + 1; i <= c; i++) {
long long gd = a * b / __gcd(a * b, i);
if ((b + 1 ) % gd == 0) {
cout << i << " " << b + 1 << endl;
return;
}
if (d % gd == 0) {
cout << i << " " << d << endl;
return;
}
if ((b + 1 ) / gd == d / gd) {
continue;
}
cout << i << " " << d / gd *gd << endl;
return;
}
cout << -1 << " " << -1 << endl;
return;
}
int main() {
int n;
cin >> n;
while (n--) {
solve();
}
return 0;
}
E2 - Divisible Numbers(hard version)
思路:相比E1,数据范围从1e5增大到1e9。关键要注意到,当我们遍历i时,有用的其实只是a*b/gcd(a*b,i),因此这其中进行了大量重复!我们自然想到,如果不遍历i,只遍历a*b/gcd(a*b,i),就能省去这些重复,而a*b/gcd(a*b,i)一定是a*b的因数!
因此本题先预处理分解质因数,再用dfs遍历所有因数。其余过程与E1相同。
时间复杂度呢?a*b的范围小于1e18,而1e18以内因数数量的最大值在11万左右(可百度查询)。因此不同担心超时问题。
代码如下:
#include <bits/stdc++.h>
using namespace std;
map<int, int> ys;
int A[100100], B[100010];
int cnt;
long long a, b, c, d, ANSX, ANSY;
long long fx(long long x) {
return (a + 1 + x - 1) / x * x;
}
void q(int x) {
for (int i = 2; i * i <= x; i++) {
while (x % i == 0) {
ys[i]++;
x /= i;
}
}
if (x > 1)
ys[x]++;
return;
}//预处理因数
long long sosolve(long long dq) {
dq = fx(dq);
if (dq <= a || dq > c)
return -1;
__int128 gd = a * b / __gcd(a * b, dq);
if ((b + 1 ) % gd == 0) {
return b + 1;
}
if (d % gd == 0) {
return d;
}
if ((b + 1 ) / gd == d / gd) {
return -1;
}
return d / gd * gd;
}
void dfs(long long dq, int step) {
if (step > cnt - 1) {
int y = sosolve(dq);
if (y != -1) {
ANSX = fx(dq);
ANSY = y;
}
return;
}
__int128 k = 1;
for (int i = 0; i <= B[step]; i++) {
dfs(dq * k, step + 1);
k *= A[step];
}
}
void solve() {
ys.clear();
cin >> a >> b >> c >> d;
q(a);
q(b);
map<int, int>::iterator t;
cnt = 0;
for (t = ys.begin(); t != ys.end(); t++) {
A[cnt] = t->first;
B[cnt] = t->second;
cnt++;
}
ANSX = -1;
ANSY = -1;
dfs(1, 0);
cout << ANSX << " " << ANSY << endl;
return;
}
int main() {
int n;
cin >> n;
while (n--) {
solve();
}
return 0;
}