牛客周赛 Round 51

youhualiuh / 2024-07-15 / 原文

对于题目我急于求AC,导致许多题没有弄到精髓只是单纯的通过而已,不思考,不磨题,太着急都是目前的BUG区域所在,于是再此改变,虽然这个过程很慢,希望能做到思考,平稳

A.小红的同余 A   小红的同余

思路+解法:

找到唯一一个x满足2x % m = 1 (0 <= x < m)  就可以推出 (m + 1) * 2即可

Code: 

#include<bits/stdc++.h>
    
using namespace std;
    
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int m; 
    cin >> m;
    cout << (m + 1) / 2;
    return 0;
}

B.小红的三倍数B   小红的三倍数

题意:

n个整数,长度很大,让你首位拼接,推出拼接后的整数是不是3的倍数

思路:

这个式子为什么能推出来(其实就是以前的知识),以下给出证明 
n = a(k) * 10^k + a(k - 1) * 10^(k - 1) + ... + a(1) * 10 + a(0) 
10^k % 3 = 1 所以就会得到  
(a(k) + a(k - 1) + a(1) + a(0)) % 3是等价于 n % 3  
证毕

如果说让你拼接的是不是其他(1 ~ 9)的倍数那能推出什么

2的倍数:最后一位数字是2的倍数

3的倍数:各位数字之和是3的倍数

4的倍数:最后两位数字组成的数是4的倍数

5的倍数:最后一位数字是5的倍数

6的倍数:同时是2和3的倍数

9的倍数:各位数字之和是9的倍数

Code:

#include<bits/stdc++.h>
    
using namespace std;
    
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int n; cin >> n;
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        string s; cin >> s;
        for (char c : s) {
            ans += (c - '0');
        }
    }
    cout << (ans % 3 ? "NO\n" : "YES");
    return 0;
}

  

C.小红充电 C   小红充电 

题意+思路:

此题已经告诉你a <= b <= c 
如果当前电量 <= t 他就一直启动着超级充电模式 每分钟c的电
如果充着电玩手机,每分钟a的电
如果不玩手机充着电,每分钟b的电
如果不充电玩手机则是每分钟损耗y的电
不难发现
-> 如果当前电量<= t它的最优测验必然是 (100 - x) / c
-> 否则会分出两种条件 
-> 1- 让我的电量先成为t开启快充模式及 (x - t) / y + (100 - t) / c;
-> 2- 就是正常充电及 (100 - x) / b
这里就会有个问题,那我玩手机充电每分钟a个电不考虑吗,其实的确不用考虑
观察到取值范围,b>=a也就是说我的2条件就已经是他们之间的最优情况了,及得出这几种情况

  

Code:

#include<bits/stdc++.h>
    
using namespace std;
    
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int x, y, t, a, b, c;
    cin >> x >> y >> t >> a >> b >> c;
    double ans = 0;
    if (x <= t) ans = (100 - x) * 1.0 / c;
    else ans = min((x - t) * 1.0 / y + (100 - t) * 1.0 / c, (100 - x) * 1.0 / b);
    cout << fixed << setprecision(10) << ans << '\n';
    return 0;
}

  

D.小红的gcd  小红的 gcd 

题意:

给你一个长度<=1e6的a,和b大小<=1e9求出gcd(a, b)

思路:

a * b % mod = (a % mod * b % mod) % mod 
(a + b) % mod = (a % mod + b % mod) % mod
是一个模运算的性质 
-> 不久可以得出累加起来套上面的
当处理大数时,我们可以将数字按位进行表示,并利用模运算的性质来简化计算。例如,对于数字 a = 12345678,可以按位分解为: 
a = 1 × 10^7 + 2 × 10^6 + 3 × 10^5 + 4 × 10^4 + 5 × 10^3 + 6 × 10^2 + 7 × 10^1 + 8 × 10^0 
这里的 10^i 表示 10 的幂次方,从右到左依次为个位、十位、百位等。根据模运算的性质,我们可以将 a % mod 表示为: 
a % mod = ((1 % mod × 10^7 % mod) + (2 % mod × 10^6 % mod) + ... + (8 % mod × 10^0 % mod)) % mod 
这种方法将大整数运算转换为小整数运算,避免溢出问题

Code:

#include<bits/stdc++.h>
    
using namespace std;
typedef long long ll;
    
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    string a;
    ll b; 
    cin >> a >> b;
    ll ans = 0;
    for (char i : a) { 
        ans = (ans * 10 + (i - '0')) % b;
    }
    cout << __gcd(ans, b);
    return 0;
}

E.小红走矩阵

这题是一道很不错的题目 也是一道很有趣的题目

题意:

定义路径权值为路径上经过的每个点的最大值,求所有路径中的最小路径权值,从(1, 1)到(n, n)找到这个最小的路径权值

bfs+二分

是因为枚举的这个最小权值它是满足单调性所以可以通过二分来枚举,也是第一次尝试

Code:

#include<bits/stdc++.h>
    
using namespace std;
const int N = 5e2 + 5;
int n, a[N][N];
bool vis[N][N];
int dirs[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};

bool check(int x, int y) {
    return x >= 1 && x <= n && y >= 1 && y <= n;
}
 
bool bfs (int mid) { 
    memset(vis, 0, sizeof(vis));
    queue <pair<int, int>> q;
    q.push({1, 1}); vis[1][1] = 1;
    while (!q.empty()) {
        auto [x, y] = q.front(); q.pop();
        if (x == n && y == n) return 1;
        for (int i = 0; i < 4; ++i) {
            int dx = dirs[i][0] + x;
            int dy = dirs[i][1] + y;
            if (check(dx, dy) && !vis[dx][dy] && a[dx][dy] <= mid) {
                vis[dx][dy] = 1;
                q.push({dx, dy});
            }
        }
    }
    return 0;
}

void check2() {
    int l = a[1][1], r = 1e9 + 1, ans;
    while (l <= r) {
        int mid = l + ((r - l) >> 1); 
        if (bfs(mid)) 
            ans = mid, r = mid - 1; 
        else 
            l = mid + 1;
    }
    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) cin >> a[i][j];
    check2(); 
    return 0;
}

  

Kruskal算法

Code:

#include <bits/stdc++.h>
using namespace std; 

const int N = 5e2 * 5e2 + 10; 
int n, a[510][510] 
 
struct Edge {
    int from, to, w;
    bool operator < (const Edge& other) const {
        return w < other.w; 
    }
};

vector<Edge> edges; 

// 二维->一维
int solve(int from, int to) {
    return (from - 1) * n + to;
}

// 添加边的函数
void addEdges(int from, int to, int w) { 
    edges.push_back({from, to, w});
}

// 并查集 
struct DSU { 
    int f[N], sz[N];
    void init(int n) {
        for (int i = 1; i <= n * n; i++) { // 注意初始化大小应为 n * n
            f[i] = i, sz[i] = 1;
        }
    }
    int find(int x) {  
        return f[x] == x ? x : f[x] = find(f[x]);
    }
    void merge (int x, int y) {  
        x = find(x); y = find(y);
        if (x == y) return;
        if (sz[x] < sz[y]) swap(x, y);
        sz[x] += sz[y];
        f[y] = x;
    }
    bool isSame (int x, int y) {  
        return find(x) == find(y);
    }
}; 

DSU dsu; 

// Kruskal算法
void Kruskal() { 
    sort(edges.begin(), edges.end());
    dsu.init(n); 
    for (Edge edge : edges) {
        int from = edge.from, to = edge.to, w = edge.w; 
        if (!dsu.isSame(from, to)) { 
            dsu.merge(from, to);  
            if (dsu.isSame(solve(1, 1), solve(n, n))) {
                cout << w << '\n';
                return;
            }
        }
    } 
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; ++i) 
        for (int j = 1; j <= n; ++j) 
            cin >> a[i][j];
    for (int i = 1; i < n; ++i) 
        for (int j = 1; j <= n; ++j) 
            addEdges(solve(i, j), solve(i + 1, j), max(a[i][j], a[i + 1][j]));
    for (int i = 1; i <= n; ++i) 
        for (int j = 1; j < n; ++j) 
            addEdges(solve(i, j), solve(i, j + 1), max(a[i][j], a[i][j + 1]));
    Kruskal();
    return 0;
}

类似题推荐

https://leetcode.cn/problems/path-with-minimum-effort/description/