牛客小白月赛33

A-字符统计

题意

给定一段字符,统计行数、单词数和字符数。

方法

getline()读取每一行字符串即可。

C++代码
#include <bits/stdc++.h>

using namespace std;

int main() {
    int T;
    cin >> T;
    cin.get();
    while (T--) {
        string s;
        int lines = 0, words = 0, ch = 0;
        while (getline(cin, s) && s != "=====") {
            lines++;
            ch += s.size();
            for (int i = 0; i < (int) s.size(); ++i) {
                if (s[i] != ' ') {
                    words++;
                    while (i < (int) s.size() && s[i] != ' ') i++;
                }
            }
        }
        cout << lines << ' ' << words << ' ' << ch << '\n';
    }
    
    return 0;
}

D-购物

题意

给定\(S\)种商品和每种商品的数量,已知\(N\)个人所拥有的商品,每个人都要凑齐所有商品种类,问剩余的商品种类数。

方法

按题意模拟即可。

C++代码
#include <bits/stdc++.h>

using namespace std;

int main() {
    int T;
    cin >> T;
    while (T--) {
        int n, m;
        cin >> n >> m;
        map<string, int> cnt;
        while (n--) {
            string s;
            cin >> s;
            int t;
            cin >> t;
            cnt[s] = t;
        }
        while (m--) {
            int k;
            cin >> k;
            set<string> has;
            while (k--) {
                string s;
                cin >> s;
                has.insert(s);
            }
            for (auto& [u, v] : cnt) {
                if (has.find(u) == has.end()) {
                    v--;
                }
            }
        }
        
        int ans = 0;
        for (auto& [u, v] : cnt) {
            if (v > 0) ans++;
        }
        
        if (ans == 0) {
            cout << "Need to be lucky\n";
        } else {
            cout << ans << '\n';
        }
    }
    
    return 0;
}

B-连分数

题意

给定一个分数,问能否写成连分数的形式。

示例
输入
3
103 24
21 73
4 2
输出
103/24 = 4+1/{3+1/{2+1/3}}
21/73 = 0+1/{3+1/{2+1/10}}
4/2 = 2
方法

观察可得,每个分数都可以写成商加上一个分子为1的分数的形式,递归计算即可。

C++代码
#include <bits/stdc++.h>

using namespace std;

void recur(int so, int mo, int& le) {
    cout << so / mo;
    if (so % mo) {
        cout << "+1/";
        so %= mo;
        if (mo % so) {
            cout << "{";
            le++;
        }
        recur(mo, so, le);
    }
}

int main() {
    int T;
    cin >> T;
    while (T--) {
        int so, mo;
        cin >> so >> mo;
        cout << so << "/" << mo << " = ";
        
        int le = 0;
        recur(so, mo, le);
        while (le--) {
            cout << "}";
        }
        cout << '\n';
    }
    
    return 0;
}

E-喝可乐

题意

给定两种可乐,价钱相同,其中\(A\)个第1种可乐的空瓶子可以兑换\(1\)瓶第2种可乐,\(B\)个第2种可乐的空瓶子可以兑换\(1\)瓶第1种可乐。已知身上的钱只能买\(n\)瓶可乐,问可以喝到的可乐的最大数量。

方法

按题意模拟即可。

C++代码
#include <bits/stdc++.h>

using namespace std;

int main() {
    int T;
    cin >> T;
    while (T--) {
        int n, a, b;
        cin >> n >> a >> b;
        
        int ans = 0;
        for (int i = 0; i <= n; ++i) {
            int c1 = i, c2 = n - i, res = c1 + c2;
            while (c1 >= a || c2 >= b) {
                if (c1 >= a) {
                    c2 += c1 / a;
                    res += c1 / a;
                    c1 %= a;
                }
                if (c2 >= b) {
                    c1 += c2 / b;
                    res += c2 / b;
                    c2 %= b;
                }
            }
            ans = max(ans, res);
        }
        
        cout << ans << '\n';
    }
    
    return 0;
}

F-天旋地转

题意

在二维平面上给定\(6\)种操作,分别是将坐标系顺时针旋转90°、逆时针旋转90°,向前、向后、向左、向右走\(k\)个单位。已知初始位置和面向方向,问最终的位置。

方法

按题意模拟即可。

C++代码
#include <bits/stdc++.h>

using namespace std;
using ll = long long;

void change(int d, char s, int k, ll& x, ll& y) {
    if (d == 0) {
        if (s == 'w') y += k;
        else if (s == 's') y -= k;
        else if (s == 'd') x += k;
        else x -= k;
    } else if (d == 1) {
        if (s == 'w') x -= k;
        else if (s == 's') x += k;
        else if (s == 'd') y += k;
        else y -= k;
    } else if (d == 2) {
        if (s == 'w') y -= k;
        else if (s == 's') y += k;
        else if (s == 'd') x -= k;
        else x += k;
    } else {
        if (s == 'w') x += k;
        else if (s == 's') x -= k;
        else if (s == 'd') y -= k;
        else y += k;
    }
}

int main() {
    int T;
    cin >> T;
    while (T--) {
        int q;
        cin >> q;
        
        ll x = 0, y = 0;
        int d = 0;
        while (q--) {
            char s;
            int k;
            cin >> s >> k;
            
            if (s == 'r') {
                d = (d + k) % 4;
            } else if (s == 'l') {
                d = (d - k + (k / 4 + 1) * 4) % 4;
            } else {
                change(d, s, k, x, y);
            }
        }
        
        cout << x << ' ' << y << '\n';
    }
    
    return 0;
}

I-三角尼姆

题意

给定一个边长为\(n\)的正三角形棋盘,每次可以摆放一枚或三枚棋子且保证所放棋子成直线。已知两个人先后下棋,最后一个放下棋子的人是输家,问是哪位。

方法

假设棋盘总空位数为奇数,则先手无论怎么下,后手都可以让先手面对的棋盘剩余空位数始终保持为奇数,此时先手必输。偶数同理。

C++代码
#include <bits/stdc++.h>

using namespace std;

int main() {
    int T;
    cin >> T;
    while (T--) {
        int n;
        cin >> n;
        
        int sum = 0;
        for (int i = 1; i <= n; ++i) sum += i;
        
        if (sum & 1) cout << "Alice\n";
        else cout << "Bob\n";
    }
    
    return 0;
}

J-线段的交

题意

给定两条线段的四个端点,如果两线段相交则求出四点围成的四边形面积,保证不存在某条线段的端点在另一条线段上。

方法

根据向量积判断两线段是否相交,然后取其中三个点逆时针排序从而根据公式计算三角形的面积,四边形的面积是其两倍。

C++代码
#include <bits/stdc++.h>

using namespace std;

struct Point {
    double x, y;
    
    Point() {}
    Point(double x, double y) : x(x), y(y) {}
    
    bool operator<(const Point& r) const {
        return x < r.x;
    }
};

// 计算叉积
double get_mul(Point p1, Point p2, Point p0) {
    double x1 = p1.x - p0.x, x2 = p2.x - p0.x;
    double y1 = p1.y - p0.y, y2 = p2.y - p0.y;
    
    return x1 * y2 - x2 * y1;
}

bool check_cross(Point p1, Point p2, Point p3, Point p4) {
    bool ok = get_mul(p2, p3, p1) * get_mul(p2, p4, p1) < 0;
    if (ok) {
        ok = get_mul(p1, p4, p3) * get_mul(p2, p4, p3) < 0;
    }
    
    return ok;
}

double get_dis(Point p1, Point p2) {
    return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}

double get_tri_area(Point p1, Point p2, Point p3) {
    double t1 = p1.x * p2.y + p2.x * p3.y + p3.x * p1.y;
    double t2 = p1.x * p3.y + p2.x * p1.y + p3.x * p2.y;
    
    return 1. / 2 * (p1.x * p2.y + p2.x * p3.y + p3.x * p1.y - p1.x * p3.y - p2.x * p1.y - p3.x * p2.y);
}

int main() {
    Point p1, p2, p3, p4;
    cin >> p1.x >> p1.y >> p2.x >> p2.y >> p3.x >> p3.y >> p4.x >> p4.y;
    
    if (check_cross(p1, p2, p3, p4)) {
        double ans = 0;
        // p1, p2, p3必须逆时针排列
        if (get_mul(p3, p2, p1) < 0) {
            ans = get_tri_area(p1, p2, p3) + get_tri_area(p1, p4, p2);
        } else {
            ans = get_tri_area(p1, p3, p2) + get_tri_area(p1, p2, p4);
        }
        cout << setprecision(8) << ans << '\n';
    } else {
        cout << 0 << '\n';
    }
    
    return 0;
}

G-切圈圈

题意

给定一个环形数组且数组和为0,问最多可以将数组切割成多少个片段。

方法

求前缀和,若两前缀和相等,则说明两点间的数组和为0,可以切割。

C++代码
#include <bits/stdc++.h>

using namespace std;

int main() {
    int T;
    cin >> T;
    while (T--) {
        int n;
        cin >> n;
        vector<int> a(n);
        for (int& x : a) cin >> x;
        
        vector<int> pre(n);
        map<int, vector<int>> mp;
        vector<int> res(n);
        for (int i = 0; i < n; ++i) {
            if (i == 0) pre[i] = a[i];
            else pre[i] = pre[i - 1] + a[i];
            if (mp.count(pre[i])) {
                int j = mp[pre[i]].back();
                res[i] = res[j] + 1;
            } else {
                res[i] = 0;
            }
            mp[pre[i]].emplace_back(i);
        }
        
        int ans = 1;
        for (int i = 0; i < n; ++i) ans = max(ans, res[i] + 1);
        
        cout << ans << '\n';
    }
    
    return 0;
}

H-货物运输

题意

给定\(n\)座城市,任务是将\(f\)箱货物从\(st\)城市运送到\(ed\)城市。有\(m\)种从一个城市运送货物到另一个城市的方案,每个方案\(P_i\)\(C_i\)每箱的价格将\(D_i\)箱货物从\(A_i\)运到\(B_i\),如果货物数量大于\(D_i\),则多出来的每箱按\(C_i'\)的价格运送。问最小的花费。

方法

简单的单源汇最短路问题,\(dijkstra\)\(spfa\)算法均可。

C++代码
#include <bits/stdc++.h>

using namespace std;
using ll = long long;

const int N = 110, M = 10010;

int h[N], e[M], ne[M], idx;
ll w[M];
int n, m, st, ed, f;
int a, b, c1, d, c2;
ll dist[N];
bool vis[N];

void add(int a, int b, ll c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

ll spfa() {
    memset(dist, 0x7f, sizeof dist);
    memset(vis, false, sizeof vis);
    
    dist[st] = 0;
    queue<int> que;
    que.push(st);
    vis[st] = true;
    while (!que.empty()) {
        int u = que.front();
        que.pop();
        vis[u] = false;
        for (int i = h[u]; ~i; i = ne[i]) {
            int v = e[i];
            if (dist[v] > dist[u] + w[i]) {
                dist[v] = dist[u] + w[i];
                if (!vis[v]) {
                    que.push(v);
                    vis[v] = true;
                }
            }
        }
    }
    
    return dist[ed];
}

int main() {
    int T;
    cin >> T;
    while (T--) {
        memset(h, -1, sizeof h);
        idx = 0;
        
        cin >> n >> m >> st >> ed >> f;
        while (m--) {
            cin >> a >> b >> c1 >> d >> c2;
            ll w = 1LL * c1 * min(f, d) + 1LL * c2 * max(0, f - d);
            add(a, b, w);
        }
        
        cout << spfa() << '\n';
    }
    
    return 0;
}
posted @ 2021-04-20 17:31  zh_alt  阅读(97)  评论(0)    收藏  举报