【CF】Day57——Codeforces Round 955 (Div. 2, with prizes from NEAR!) BCD
B. Collatz Conjecture
题目:
思路:
简单模拟
很简单的模拟,我们只需要快速的找到下一个离 x 最近的 y 的倍数即可(要大于 x)
这里我们可以这样写 add = y - (x % y),这样就知道如果 x 要变成 y 的倍数还要增加多少个数
然后模拟即可
注意,这样操作有限次后如果 k 足够,那么最后 x 一定会变成 1,此时将进入一个循环,每经过 k - 1 此后 x 又会变成 1,这样我们就能很快算出来了
代码:
#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"void solve()
{int x, y, k;cin >> x >> y >> k;while (k && x!= 1){int add = min(k, y - (x % y));x += add;k -= add;while (x % y == 0){x /= y;}}k %= (y - 1);x += k;while (x % y == 0){x /= y;}cout << x << endl;
}signed main()
{cin.tie(0)->sync_with_stdio(false);int t = 1;cin >> t;while (t--){solve();}return 0;
}
C. Boring Day
题目:
思路:
双指针练习题
由于我们只能从左往后选,那么可以想到使用双指针来解决
我们定义双指针 L~R
sum < l,那么就增加右指针继续选
sum >= l && sum <= r,那么就结束选择,并且清零
sum > r,那么就增加左指针并且要减去之前的左指针的值
为什么这样呢?这其实是贪心的想法,因为我们要尽可能选的多,所以我们到了就立马结束,同时如果不行的话,由于我们只能从左往右选,所以我们删去左边的是正确的,且能给后面更多机会
代码:
#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"void solve()
{int n, l, r;cin >> n >> l >> r;vector<int> a(n + 5, 1e18);int res = 0;for (int i = 0; i < n; i++){cin >> a[i];}int L = 0, R = -1, sum = 0;while (L < n && R < n){if (sum >= l && sum <= r){res++;L = R + 1;sum = 0;}else if (sum < l){R++;sum += a[R];}else if (sum > r){sum -= a[L];L++;}}cout << res << endl;
}signed main()
{cin.tie(0)->sync_with_stdio(false);int t = 1;cin >> t;while (t--){solve();}return 0;
}
D. Beauty of the mountains
题目:
思路:
二维前缀和 + 裴蜀定理
这题目乍一看我们好像没啥思路,我们来简单分析一下试试
首先如果要改某个变 k*k 子矩阵中的数字,那么肯定有 ,其中cnt是这个子矩阵内 0/1 的数量,c 是一个任意变量
那如果我们所有可能加起来我们会发现有以下式子
其中每个 c 都是未知量,但是每个子矩阵的 cnt1 和 cnt0 都是已知量,且最后 h 的变化量一定就是我们所需要改变的量,那么就可以化为
仔细观察这个式子,我们可以发现这其实就是多个未知量时的裴蜀定理
那么有解条件就是满足 gcd(a,b,c,...) | h = 0
所以我们可以先将所有可能的子矩阵的cnt0和cnt1记录下来,然后枚举每一个子矩阵来计算常数 abc.. 最后跑一边 gcd 然后看看是否能同余 h 为 0即可
具体的,我们使用一个二维前缀和来记录 i*j 矩阵中的 1 的数量,这样 0 的数量就是 k * k - cnt1,然后我们枚举每一个k*k子矩阵的起点即可
实现部分看代码,有点细节
代码:
#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"int gcd(int a,int b)
{return !b ? a : gcd(b, a % b);
}void solve()
{int n, m, k;cin >> n >> m >> k;vector<vector<int>> a(n+1, vector<int>(m+1));for (int i = 1; i <= n; i++){for (int j = 1; j <= m; j++){cin >> a[i][j];}}vector<string> s(n+1);for (int i = 1; i <= n; i++){cin >> s[i];s[i] = " " + s[i];}int diff = 0;vector<vector<int>> pre(n+2, vector<int>(m+1,0));for (int i = 1; i <= n; i++){for (int j = 1; j <= m; j++){pre[i][j] = pre[i-1][j] + pre[i][j-1] - pre[i-1][j-1];if (s[i][j] == '1'){pre[i][j]++;diff += a[i][j];}else{diff -= a[i][j];}}}if (diff == 0){yes;return;}int g = 0;k--;for (int i = 1; i <= n - k; ++i) {for (int j = 1; j <= m - k; ++j) {int f = pre[i + k][j + k] - pre[i + k][j-1] - pre[i-1][j + k] + pre[i-1][j-1];f = abs((k+1) * (k+1) - 2 * f);g = gcd(g, f);}}if (g == 0 || abs(diff) % g != 0) {no;}else {yes;}
}signed main()
{cin.tie(0)->sync_with_stdio(false);int t = 1;cin >> t;while (t--){solve();}return 0;
}