第二周训练题单

多项式输出

小细节比较多

#include <bits/stdc++.h>

using namespace std;

#define int long long


int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int n;
    cin >> n;
    for (int x , i = n ; i >= 0; i--) {
        cin >> x;
        if( x == 0 ) continue;
        if (x < 0) cout << "-", x = -x;
        else if( i != n )  cout << "+";
        if (x > 1 || i == 0 ) cout << x;
        if( i > 1 ) cout << "x^" << i;
        else if( i == 1 ) cout << "x";
    }
    return 0;
}

铺地毯

根本不需要维护整张图,读入所有地毯倒序枚举判断一下就好了。

#include <bits/stdc++.h>

using namespace std;

#define int long long

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int n;
    cin >> n;
    vector<int> a(n+1) , b(n+1) , c(n+1) , d(n+1);
    for( int i = 1 ; i <= n ; i ++ )
        cin >> a[i] >> b[i] >> c[i] >> d[i] , c[i] +=a[i] , d[i] += b[i];
    int x , y;
    cin >> x >> y;
    for( int i = n ; i >= 1 ; i -- )
        if( a[i] <= x && x <= c[i] && b[i] <= y && y <= d[i] )
            cout << i , exit(0);
    cout << "-1\n";
    return 0;
}

第k小

因为 k 值不变,所以直接维护大小为 k 的堆就好了。

#include <bits/stdc++.h>

using namespace std;

#define int long long

const int mod = 998244353;


int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int n, m, k;
    cin >> n >> m >> k;
    priority_queue<int> q;
    for (int x; n; n--)
        cin >> x, q.emplace(x);
    while (q.size() > k) q.pop();
    for( int op , x ; m ; m -- ){
        cin >> op;
        if( op == 1 ){
            cin >> x , q.emplace(x);
            while (q.size() > k) q.pop();
        }else{
            if(q.size() < k ) cout << "-1\n";
            else cout << q.top() << "\n";
        }
    }
    return 0;
}

丢手绢

实际上,在总长度不超过半径时,问任意子区间的最大值,要注意的是,这里是环,所以要进行破环成链,这里我采用了循环坐标,当然也可使用存两遍。区间最大值用双指针就能很好的解决。

#include <bits/stdc++.h>

using namespace std;

#define int long long

const int mod = 998244353;


int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int n, C = 0;
    cin >> n;
    vector<int> a(n);
    for (auto &i: a)
        cin >> i, C += i;
    int res = 0;
    for (int l = 0, r = -1, cnt = 0; l < n ; l++) {
        while ( cnt * 2 <= C) {
            r = ( r + 1 ) % n , cnt += a[r];
            res = max(res, min(cnt, C - cnt));
        }
        cnt -= a[l];
    }
    cout << res << "\n";
    return 0;
}

中位数图

规定 x 是子区间内比 b 大的数的数量,y 是子区间内比 b 小的数的数量

首先我们统计 b 的一侧,每个位置上x-y的值。然后再遍历另一侧,对于当前的x,y,看另一侧有多少y-x

#include <bits/stdc++.h>

using namespace std;

#define int long long

const int mod = 998244353;

#define mp make_pair

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int n, m, P = -1, res = 0;
    cin >> n >> m;
    vector<int> a(n);
    for (auto &i: a) cin >> i;
    for (int i = 0; P == -1 && i < n; i++)
        if (a[i] == m) P = i;
    map<int, int> cnt;
    for (int i = P, x = 0, y = 0; i >= 0; i--) {
        if (a[i] > m) x++;
        if (a[i] < m) y++;
        cnt[x - y]++;
    }
    for (int i = P, x = 0, y = 0; i < n; i++) {
        if (a[i] > m) x++;
        if (a[i] < m) y++;
        res += cnt[y - x];
    }
    cout << res << "\n";
    return 0;
}

好串

括号匹配

#include <bits/stdc++.h>

using namespace std;

#define int long long

const int mod = 998244353;

#define mp make_pair

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    string s;
    cin >> s;
    int cnt = 0;
    for (auto i: s) {
        if (i == 'a') cnt++;
        else cnt--;
        if (cnt < 0) {
            cout << "Bad\n";
            return 0;
        }
    }
    if (cnt == 0) cout << "Good\n";
    else cout << "Bad\n";
    return 0;
}

兔子的区间密码

在二进制下考虑,从高位开始枚举,遇到第一位l!=r的,一个数当前位置 1 其他位置 0,另一个数当前位置 0 其他位置 1。

#include <bits/stdc++.h>

using namespace std;

#define int long long

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

void solve(){
    int l = read() , r = read();
    int i = 63;
    for( ; i >= 0 ; i -- )
        if( (l>>i) != (r>>i) ) break;
    printf("%lld\n" , (1ll << (i+1))-1 );
    return;
}

int32_t main() {
    for(int T = read(); T ; T--)
        solve();
    return 0;
}

道路建设

最小生成树

#include <bits/stdc++.h>

using namespace std;

struct dsu {
    vector<int> fa;

    dsu(int n = 0) : fa(n + 1, -1) {};

    int getfa(int x) {
        if (fa[x] < 0) return x;
        return fa[x] = getfa(fa[x]);
    }

    bool merge(int x, int y) {
        x = getfa(x), y = getfa(y);
        if (x == y) return false;
        if (fa[x] > fa[y]) swap(x, y);
        fa[x] += fa[y], fa[y] = x;
        return true;
    }

    int size(int x) {
        x = getfa(x);
        return -fa[x];
    }
};


int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int c, n, m;
    cin >> c >> m >> n;
    dsu d(n);
    vector<tuple<int, int, int>> e(m);
    for (auto &[w, x, y]: e)
        cin >> x >> y >> w;
    sort(e.begin(), e.end());
    for (const auto &[w, x, y]: e)
        if (d.merge(x, y)) c -= w;
    if (c >= 0 && d.size(1) == n ) cout << "Yes\n";
    else cout << "No\n";
    return 0;
}

逛公园

反向建图跑最短路,正向记忆化搜索。

f[i][j]表示从起点走到点i多花费了j的方案数。

#include <bits/stdc++.h>

using namespace std;

#define int long long

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

int n, m, k, P, flag;
vector<int> dis;
vector<vector<pair<int, int>>> e, g;
vector<vector<int>> f;
vector<vector<bool>> cnt;

void dij() {
    dis = vector<int>(n + 1, INT_MAX);
    dis[n] = 0;
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
    q.emplace(0, n);
    vector<bool> vis(n + 1, false);

    while (!q.empty()) {
        auto [d, u] = q.top();
        q.pop();
        if (vis[u]) continue;
        vis[u] = true;
        for (auto [v, w]: g[u]) {
            if ( dis[v] <= d + w) continue;
            dis[v] = d + w, q.emplace(dis[v], v);
        }
    }
    return;
}

int calc(int u, int t) {
    if (cnt[u][t]) {
        flag = 0;
        return 0;
    }
    if (f[u][t] != -1) return f[u][t] % P;
    cnt[u][t] = true;
    f[u][t] = 0;
    for (const auto &[v, w]: e[u]) {
        int p = t - (dis[v] + w - dis[u]);
        if (p >= 0) f[u][t] = (f[u][t] + calc(v, p)) % P;
        if (flag == 0) return 0;
    }
    cnt[u][t] = false;
    if (u == n && t == 0) f[n][0] = 1;
    return f[u][t] % P;
}

void solve() {
    n = read(), m = read(), k = read(), P = read();
    e = vector<vector<pair<int, int>>>(n + 1), g = vector<vector<pair<int, int>>>(n + 1);
    for (int u, v, w; m; m--) {
        u = read(), v = read(), w = read();
        e[u].emplace_back(v, w), g[v].emplace_back(u, w);
    }
    dij();
    f = vector<vector<int>>(n + 1, vector<int>(k + 1, -1));
    flag = 1;
    cnt = vector<vector<bool>>(n + 1, vector<bool>(k + 1, false));
    int res = 0;
    for (int i = 0; flag && i <= k; i++)
        res = (res + calc(1, i)) % P;
    if (flag == 0) res = -1;
    printf("%lld\n", res);
    return;
}

int32_t main() {
    for (int T = read(); T; T--)
        solve();
    return 0;
}

求先序排列

二叉树还原

#include <bits/stdc++.h>

using namespace std;

#define int long long

string getPrefer(string middle, string suffer) {
    if (middle.size() <= 1 ) {
        return middle;
    }
    int p;
    for (p = 0; p < middle.size(); p++)
        if (middle[p] == suffer.back()) break;
    string lMiddle = middle.substr(0, p);
    string rMiddle = middle.substr(p + 1);
    string lSuffer = suffer.substr(0, p);
    string rSuffer = suffer.substr(p , rMiddle.size());
    return suffer.back() + getPrefer(lMiddle, lSuffer) + getPrefer(rMiddle, rSuffer);
}

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    string middle, suffer;
    cin >> middle >> suffer;
    cout << getPrefer(middle, suffer);
}

数字组合

改变枚举的顺序

#include <bits/stdc++.h>

using namespace std;

#define int long long

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int n;
    cin >> n;
    vector<int> a (n) , b(n) , c(n) , d(n);
    for( int i = 0 ; i < n ; i ++ )
        cin >> a[i] >> b[i] >> c[i] >> d[i];
    map<int,int> cnt;
    for( auto i : a )
        for( auto j : b )
            cnt[ i + j ] ++;
    int res =0;
    for( auto i : c )
        for( auto j : d )
            res += cnt[ - i - j ];
    cout << res << "\n";
    return 0;
}

Protecting the Flowers

贪心

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>


using namespace std;

#define int long long
struct node{
    int t , d;
};
bool cmp( node a , node b ){
    return a.t * b.d < b.t * a.d;
}

signed main() {
    int n , res = 0 , cnt = 0;
    cin >> n;
    vector<node> a(n);
    for( int i = 0 ; i < n ; i ++ )
        cin >> a[i].t >> a[i].d;
    sort( a.begin() , a.end() , cmp );
    for( int i = 0 ; i < n ; i ++ ){
        res += cnt * a[i].d , cnt += 2ll * a[i].t;
    }
    cout << res;
    return 0;
}

小咪买东西

\[\frac{\sum v}{\sum c } = \max\\ \sum v - \max\sum c = \sum( v - \max c) = 0 \]

这样的话我们可以二分\(\max\),如果枚举的值是\(x\),先计算出\(y_i=v_i-xc_i\)然后选择前 k 大,判断和和零的大小即可。

#include <bits/stdc++.h>

using namespace std;

#define int long long
const double eps = 1e-6;

void solve() {
    int n, k;
    cin >> n >> k;
    vector<double> c(n), v(n);
    for (int i = 0; i < n; i++)
        cin >> c[i] >> v[i];
    auto f = [n, k, c, v](double x) {
        vector<double> y;
        for (int i = 0; i < n; i++)
            y.push_back(v[i] - x * c[i]);
        sort(y.begin(), y.end(), greater<int>());
        double cnt = 0;
        for (int i = 0; i < k; i++)
            cnt += y[i];
        return cnt < 0 ;
    };

    double l = 0, r = 1e9, mid, res = -1;
    while ( r-l > eps ) {
        mid = (l + r) / 2.0;
        if (f(mid)) res = mid, r = mid - eps;
        else l = mid + eps;
    }
    cout << (int)res << "\n";
    return;
}

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int t;
    cin >> t;
    while (t--)
        solve();
    return 0;
}

星球大战

模拟

#include <bits/stdc++.h>

using namespace std;

#define int long long

const int mod = 998244353;

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int n, m;
    cin >> n >> m;
    map<int, multiset<int>> cntX, cntY;
    for (int x, y; n; n--) {
        cin >> x >> y;
        cntX[x].emplace(y);
        cntY[y].emplace(x);
    }
    for (int c, d; m; m--) {
        cin >> c >> d;
        if (c == 0) {
            cout << cntX[d].size() << "\n";
            for (auto y: cntX[d])
                cntY[y].erase(cntY[y].lower_bound(d));
            cntX[d].clear();
        } else {
            cout << cntY[d].size() << "\n";
            for (auto x: cntY[d])
                cntX[x].erase(cntX[x].lower_bound(d));
            cntY[d].clear();
        }
    }
    return 0;
}

叠积木

用并查集维护合并的过程,同时额外维护当前点到祖先节点的距离,注意在路径压缩的时候更新距离

#include <bits/stdc++.h>

using namespace std;

#define int long long

struct dsu {
    vector<int> fa, dis;

    dsu(int n = 0) : fa(n + 1, -1), dis(n + 1, 0) {};

    int getFa(int x) {
        if (fa[x] < 0) return x;
        int t = fa[x], p = getFa(fa[x]);
        dis[x] += dis[t], fa[x] = p;
        return fa[x];
    }

    void merge(int x, int y) {
        x = getFa(x), y = getFa(y);
        dis[x] = -fa[y];
        fa[y] += fa[x], fa[x] = y;
    }

    int d(int x) {
        getFa(x);
        return dis[x];
    }
};


int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int q;
    cin >> q;
    dsu d(30000);
    while (q--) {
        string op;
        cin >> op;
        if (op == "M") {
            int x, y;
            cin >> x >> y;
            d.merge(x, y);
        } else {
            int x;
            cin >> x;
            cout << d.d(x) << "\n";
        }
    }
    return 0;
}

传送带

考虑到精度要求不高,直接暴力的把线段分成5000个点,然后暴力枚举

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
typedef pair<double, double> vec;

vec operator-(vec a, vec b) {
    a.first -= b.first, a.second -= b.second;
    return a;
}

vec operator+(vec a, vec b) {
    a.first += b.first, a.second += b.second;
    return a;
}

vec operator/(vec a, double x) {
    a.first /= x, a.second /= x;
    return a;
}

double dis(vec a, vec b) {
    return sqrt((a.first - b.first) * (a.first - b.first) + (a.second - b.second) * (a.second - b.second));
}

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    vec A, B, C, D;
    double p, q, r;
    cin >> A.first >> A.second >> B.first >> B.second >> C.first >> C.second >> D.first >> D.second >> p >> q >> r;
    auto d = (B - A) / 5000;
    vector<vec> t;
    int ct = 5000;
    for (auto i = A; ct; ct--, i = i + d)
        t.push_back(i);
    t.push_back(B);
    d = (D - C) / 5000;
    vector<vec> s;
    ct = 5000;
    for (auto i = C; ct; ct--, i = i + d)
        s.push_back(i);
    s.push_back(D);
    double res = LDBL_MAX;
    for (auto i: t)
        for (auto j: s) {
            double cnt = dis(A, i) / p + dis(i, j) / r + dis(j, D) / q;
            res = min(res, cnt);
        }
    cout << fixed << setprecision(2) << res << "\n";
    return 0;
}

Look Up

单调栈?

#include <bits/stdc++.h>

using namespace std;

#define int long long


int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int n;
    cin >> n;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++) cin >> a[i];

    stack<int> s;
    vector<int> res(n + 1, 0);
    for (int i = 1; i <= n; i++) {
        while (!s.empty() && a[s.top()] < a[i])
            res[s.top()] = i, s.pop();
        s.push(i);
    }
    for (int i = 1; i <= n; i++)
        cout << res[i] << "\n";

    return 0;
}
posted @ 2023-07-25 18:26  PHarr  阅读(23)  评论(0编辑  收藏  举报