牛客周赛51
A 小红的同余
给出一个奇数
void solve() {
int n;cin >> n;
cout << (n + 1) / 2 << '\n';
}
B 小红的三倍数
现在有
判断一个数是不是三的倍数只需要看它的各位之和是不是三的倍数即可
void solve() {
int n;cin >> n;
int sum = 0;
for (int i = 1;i <= n;i++) {
string s;cin >> s;
for (auto x : s)sum += x - '0';
}
if (sum % 3 == 0) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}
C 小红充电
小红手机充满电是 100%,现在手机有
由题目容易知道:
当
当
- 直接按照当前最快速度充电直至充满
- 先将电量玩到
,然后直接超级充电
void solve() {
cout << setprecision(10);
int x, y, t, a, b, c;cin >> x >> y >> t >> a >> b >> c;
if (x <= t) {
cout << (100 - x) * 1.0 / c << '\n';
} else {
cout << min((100 - x) * 1.0 / max(a, b), (100 - t) * 1.0 / c + (x - t) * 1.0 / y) << '\n';
}
}
D 小红的 gcd
给两个正整数
Solution
大数取模
即一个大数和一个 int 数求 gcd
易得:gcd (a, b)=gcd (b, a%b)
即求 x=a%b,ans=gcd (b, x)
运用性质:多个因子连续的乘积取模的结果等于每个因子取模后的乘积再取模的结果
即:
由此性质,可以将 a 分为若干块,假设每次分割 9 位数字
只需要一位一位计算即可。
则
#define int long long
void solve() {
string a;int b;cin >> a >> b;
vector<int> ans;
for (int i = 0;i < a.size();i += 9) {
string s = a.substr(i, 9);
ans.push_back(stoi(s));
}
int x = 0;
for (auto m : ans) {
x *= qpow(10, to_string(m).size(), b);x += m;x %= b;
}
cout << __gcd(x, b) << '\n';
}
#define int long long
void solve() {
string a;int b;cin >> a >> b;
int ans = 0;
for (auto x : a) {
ans = (ans * 10 + x - '0') % b;
}
cout << __gcd(ans, b) << '\n';
}
E 小红走矩阵
给定
Solution
BFS+二分
做法很多:二分/最短路/并查集,但 DP 不可行。
二分答案想到了应该就不难了!时间复杂度
constexpr int dx[] = {1, -1, 0, 0};
constexpr int dy[] = {0, 0, 1, -1};
int n,g[505][505];
bool check(int mid) {
if (g[0][0] > mid) return false;
vector<vector<bool>> vis(n, vector<bool>(n, false));
queue<pair<int, int>> q;
q.push({0, 0}); vis[0][0] = true;
while (!q.empty()) {
auto [x, y] = q.front();q.pop();
if (x == n - 1 && y == n - 1) return true;
for (int i = 0; i < 4; ++i) {
int nx = x + dx[i], ny = y + dy[i];
if (nx >= 0 && nx < n && ny >= 0 && ny < n && ! vis[nx][ny] && g[nx][ny] <= mid) {
q.push({nx, ny});
vis[nx][ny] = true;
}
}
}
return false;
}
int main() {
cin >> n;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
cin >> g[i][j];
}
}
int l = INT_MAX, r = INT_MIN;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
l = min(l, g[i][j]);
r = max(r, g[i][j]);
}
}
while (l < r) {
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
cout << l << '\n';
}
并查集的思路:即按权值从小到大合并,直至 (0,0)和 (n-1, m-1)连通.
F 小红的数组
小红有一个数组,这个数组中有
小红有
Solution
线段树需要维护的信息:
- 区间和 (sum),包含左端点开始的最大字段和 (lmax),右端点的 (rmax),区间最大字段和 (mmax)
- 最大值和最小值
题目其实有提示:
将 i=1 改为 i=0 后就过了?不懂
#define int long long
int f1[500010][30], f2[500010][30];
void solve() {
int n;cin >> n;
vector<int> a(n + 1), pre(n + 1);
for (int i = 1;i <= n;i++)cin >> a[i];
for (int i = 1;i <= n;i++)pre[i] = pre[i - 1] + a[i];
for (int i = 1;i <= n;i++)f1[i][0] = pre[i], f2[i][0] = f1[i][0];
for (int j = 1;j <= 30;j++) {
for (int i = 0;i + (1 << j) - 1 <= n;i++) {//将i=1改为i=0后就过了?
f1[i][j] = max(f1[i][j - 1], f1[i + (1 << (j - 1))][j - 1]);
f2[i][j] = min(f2[i][j - 1], f2[i + (1 << (j - 1))][j - 1]);
}
}
int q;cin >> q;
while (q--) {
int l, r;cin >> l >> r;l--;
int k = __lg(r - l + 1);
cout << max(f1[l][k], f1[r - (1 << k) + 1][k]) - min(f2[l][k], f2[r - (1 << k) + 1][k]) << '\n';
}
}
若这个题目改动一下:将绝对值去掉,则题目变为245. 你能回答这些问题吗 - AcWing题库