Codeforces Round 955 Div.2 A~D
A. Soccer
题目大意
有一场比赛,给定开始时刻和结束时刻双方的比分(均非平局) x 1 : y 1 x_1 : y_1 x1:y1 和 x 2 : y 2 x_2 : y_2 x2:y2, 问在这期间有没有可能从未出现双方比分相同的时刻。
思路
若开始时和结束时双方比分的大小关系相同则有可能出现上述情况。
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e5 + 5;
int a, b, c, d;
void solve() {
cin >> a >> b >> c >> d;
if ((a > b && c > d) || (a < b) && (c < d)) {
cout << "YES\n";
}
else {
cout << "NO\n";
}
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int _T = 1;
cin >> _T;
while (_T--)
solve();
return 0;
}
B. Collatz Conjecture
题目大意
给定一个变量 x , 1 ≤ x ≤ 1 0 9 x, 1 \leq x \leq 10^9 x,1≤x≤109 和一个常数 y , 2 ≤ y ≤ 1 0 9 y, 2 \leq y \leq 10^9 y,2≤y≤109, 执行 k , 1 ≤ k ≤ 1 0 9 k, 1 \leq k \leq 10^9 k,1≤k≤109 次以下操作:
- 将 x x x 增加 1 1 1
- 若 x x x 能被 y y y 整除,将 x x x 整除 y y y, 重复此步骤直到不能整除
求 k k k 次操作后 x x x 的值是多少。
思路
由于 y ≥ 2 y \geq 2 y≥2, 显然 x x x 在很少次数的操作后就会小于 y y y.
因为 x ≤ y x \leq y x≤y 后再操作, x x x 的值只会是 1 ≤ x < y 1 \leq x < y 1≤x<y. 所以模拟操作,直到 x ≤ y x \leq y x≤y
进入 x ≤ y x \leq y x≤y 后,先进行操作,使 x = 1 x = 1 x=1, 设此时还剩 K K K 次操作,由于 x x x 经过 y − 1 y-1 y−1 次操作后又会得到 1 1 1 , 那么最终 x x x 的值就是 k m o d ( y − 1 ) k \mod (y-1) kmod(y−1) .
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int x, y, k;
void solve() {
cin >> x >> y >> k;
int a = x / y;
while (a) {
int d = (a + 1) * y - x;
if (k < d) {
cout << k + x << '\n';
return;
}
k -= d;
x = a + 1;
while (x % y == 0) {
x /= y;
}
a = x / y;
}
// then x < y
int d = y - x;
if (k < d) {
cout << k + x << '\n';
return;
}
k -= d;
x = 1;
k %= (y - 1);
cout << x + k << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int _T = 1;
cin >> _T;
while (_T--)
solve();
return 0;
}
C. Boring Day
题目大意
给定一个数列 a a a, 可以随意划分这个数列,问最多有几个连续子区间,子区间内的数之和 s u m sum sum 满足 l ≤ s u m ≤ r l \leq sum \leq r l≤sum≤r.
思路
贪心+双指针模拟
在前缀中寻找一个段 ( a , b ) (a,b) (a,b),使得其所有元素的总和满足条件,并且在所有这些段中,取 b b b 最小的段。之后,从第 ( b + 1 ) (b+1) (b+1) 个元素开始,并继续以相同的方式搜索下一个段。
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 5;
int n;
ll L, R;
ll a[N];
int calc() {
int cnt = 0;
int l = 1, r = 1;
ll sum = 0;
while (r <= n) {
if (a[r] == 0) {
r++;
l = r;
sum = 0;
continue;
}
sum += a[r];
if (sum > R) {
while (sum > R) {
sum -= a[l];
l++;
}
}
if (sum >= L && sum <= R) {
cnt++;
r++;
l = r;
sum = 0;
}
else {
r++;
}
}
return cnt;
}
void solve() {
cin >> n >> L >> R;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
int res = calc();
cout << res << '\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int _T = 1;
cin >> _T;
while (_T--)
solve();
return 0;
}
D. Beauty of the mountains
题目大意
给定一个 n × m n \times m n×m 的矩阵 a a a, 和一个 n × m n \times m n×m 的 01 01 01 矩阵,和子矩阵的边长 k k k. Nikita 的目的是令所有为 0 0 0 的位置与所有为 1 1 1 的位置的数之和相等,他可以进行无限次操作:
- 选择一个 k × k k \times k k×k 的子矩阵
- 将这个矩阵中的所有数增加或减少任意值
问 Nikita 最终能否达成目标。
思路
以
n
=
4
,
m
=
3
,
k
=
3
n = 4, m = 3, k = 3
n=4,m=3,k=3 的条件为例,大矩阵中能够选择左右两个小矩阵进行操作。设整个矩阵中,对应位置为
0
0
0 和为
1
1
1 的数分别求和的差值为
d
d
d, 左子矩阵中
0
0
0 和
1
1
1 的个数差值为
c
n
t
cnt
cnt. 若子矩阵中每个数都增加
1
1
1, 则相当于
d
−
c
n
t
d-cnt
d−cnt (计算时注意相对大小), 因此若要满足目标,需要
a
b
s
(
d
)
abs(d)
abs(d) 能够整除
a
b
s
(
c
n
t
)
abs(cnt)
abs(cnt). 同理,对于右子矩阵依然。
进而能够推出,若要达到目标,需要
d
d
d 能够整除所有子矩阵的
c
n
t
cnt
cnt, 也就是
d
m
o
d
G
C
D
(
c
n
t
i
)
=
0
d \mod GCD(cnt_i) = 0
dmodGCD(cnti)=0, 或者
d
=
0
d = 0
d=0 (不需要任何操作).
由于 n , m ≤ 500 n, m \leq 500 n,m≤500, 需要对 c n t cnt cnt 求二维前缀和。
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 5e2 + 5;
int n, m, k;
string s[N];
ll a[N][N];
int sum[N][N];
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
void solve() {
int cnt1 = 0, cnt0 = 0;
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
sum[i][j] = 0;
}
}
for (int i = 1; i <= n; i++) {
cin >> s[i];
s[i] = "*" + s[i];
for (int j = 1; j <= m; j++) {
sum[i][j] = sum[i][j - 1] + (s[i][j] == '1');
}
}
for (int j = 1; j <= m; j++) {
for (int i = 1; i <= n; i++) {
sum[i][j] = sum[i - 1][j] + sum[i][j];
}
}
vector<int> v;
for (int i = 1; i <= n - k + 1; i++) {
for (int j = 1; j <= m - k + 1; j++) {
int cnt1 = sum[i - 1][j - 1] + sum[i + k - 1][j + k - 1] - sum[i - 1][j + k - 1] - sum[i + k - 1][j - 1];
int cnt0 = k * k - cnt1;
v.push_back(abs(cnt0 - cnt1));
}
}
ll d = 0;
int g = v[0];
for (int i = 1; i < v.size(); i++) {
g = gcd(g, v[i]);
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (s[i][j] == '1')
d += a[i][j];
else
d -= a[i][j];
}
}
if (d == 0 || (g && abs(d) % g == 0)) cout << "YES\n";
else cout << "NO\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int _T = 1;
cin >> _T;
while (_T--)
solve();
return 0;
}