AtCoder Beginner Contest 373 Solution

A

void solve() {
    n = 12;
    int ans = 0;
    string s;
    FOR(i, n) qr(s), ans += SZ(s) == i;
    pr2(ans);
}

B

void solve() {
    string s;
    qr(s);
    n = SZ(s);
    rep(i, 0, n - 1) a[s[i]] = i;
    rep(i, 'B', 'Z') m += abs(a[i] - a[i - 1]);
    pr2(m); 
}

C

void solve() {
    qr(n);
    VT<int> a(n), b(n);
    qr(a, b);
    pr2(ranges::max(a) + ranges::max(b));
}

D

把反向边加上,边权取负, 然后dfs即可.

int n, m;
ll v[N];
bool vis[N];
VT<pii> e[N];

void dfs(int x) {
    if(vis[x]) return;
    vis[x] = 1;
    for(auto [y, z]: e[x]) {
        v[y] = v[x] + z;
        dfs(y);
    }
}

void solve() {
    qr(n, m);
    int x, y, z;
    FOR(i, m) {
        qr(x, y, z);
        e[x].pb({y, z});
        e[y].pb({x, -z});
    }
    FOR(i, n) dfs(i);
    FOR(i, n) pr1(v[i]);
}

E

对每个人二分增加的票数, 判断是否能赢.

当他此时票数为 w w w, 则有其他 m m m 个人的票数 > w >w >w 时, 他会输.

这个时候,可以二分一下 ≤ w \le w w 的分界位置 p p p , 那么 [ n − m + 1 , p ] [n-m+1,p] [nm+1,p] 大的人需要移动到 w + 1 w+1 w+1, 用前缀和计算这个区间的总需求票数即可.

特别地, 如果他一开始就是前 m m m 大的话, 需要把他剔除, 查询区间变为 [ n − m , p ] [n-m,p] [nm,p].

int n, m, p[N];
ll a[N], b[N], s[N], ans[N];

void solve() {
    ll k;
    qr(n, m, k);
    FOR(i, n) qr(a[i]), p[i] = i;
    if(m == n) {
        FOR(i, n) pr1(0);
        return;
    }
    sort(p + 1, p + n + 1, [&](int x, int y) {return a[x] < a[y];});
    FOR(i, n) s[i] = s[i - 1] + (b[i] = a[p[i]]);
    ll res = k - s[n];
    FOR(i, n) {
        int x = p[i];
        auto check = [&](ll v) -> bool {
            ll w = v + a[x] + 1;
            if(w <= b[n - m]) return 0;
            int l = n - m, r = n, mid;
            while(l < r) {
                mid = (l + r + 1) >> 1;
                if(b[mid] < w) l = mid;
                else r = mid - 1;
            }
            v = res - v;
            if(i > n - m) {
                v -= w * (l - (n - m)) - (s[l] - s[n - m - 1] - b[i]);
            }
            else {
                v -= w * (l - (n - m)) - (s[l] - s[n - m]);
            }
            return v < 0;
        };
        ll l = 0, r = res, mid;
        while(l < r) {
            mid = (l + r) >> 1;
            if(check(mid)) r = mid;
            else l = mid + 1;
        }
        ans[x] = !check(l) ? -1: l;
    }
    FOR(i, n) pr1(ans[i]);
}

F

考虑同一个物品 ( w i , v i ) (w_i,v_i) (wi,vi) k k k 次和 k − 1 k-1 k1 次的差分, v ’ = k v − k 2 − [ ( k − 1 ) v − ( k − 1 ) 2 ] = v − 2 k − 1 v’=kv-k^2-[(k-1)v-(k-1)^2]=v-2k-1 v=kvk2[(k1)v(k1)2]=v2k1. 那么可以视作有一个物品重量为 w i w_i wi, 价值为 v ’ v’ v.

然后, 对于相同重量的物品, 我们取价值大的肯定更优.

对于重量 w w w, 至多加入 m w \dfrac m w wm 个, 那么我们只需要排序取前 m w \dfrac m w wm 大加入背包即可.

总复杂度 O ( n m + m 2 log ⁡ m ) O(nm + m^2 \log m) O(nm+m2logm).

int n, m;
ll f[N];

void add(int x, int y) {
    REP(i, x, m) 
        cmax(f[i], f[i - x] + y);
}

void solve() {
    qr(n, m);
    memset(f, -63, sizeof f);
    f[0] = 0;
    int x, y;
    VT v(m + 1, VT<int>());
    while(n--) {
        qr(x, y); y--;
        for(int i = x; i <= m; i += x) 
            v[x].pb(y), y -= 2;
    }
    FOR(i, m) {
        auto &a = v[i];
        n = m / i;
        if(SZ(a) > n) nth_element(a.begin(), a.begin() + SZ(a) - n, a.end());
        for(auto j: a | views::reverse) {
            add(i, j);
            if(!--n) break;
        }
    }
    pr2(*max_element(f, f + m + 1));
}

G

有两个点集 X , Y X, Y X,Y, 需要他们两两配对, 且相连线段不交. 最后给出配对方案.(没有点重合, 三点共线的情况. n < = 300 n<=300 n<=300.)


如图, 相交的话,长度会比不交大.
那么我们可以考虑求图的最小权匹配, 边权为欧氏距离.
最后得到的匹配就是答案.

代码1为KM算法, 代码2为暴力置换边.(代码2其实更短且更快…)

Code1:

#include <bits/stdc++.h>
#define fi first
#define se second
#define mk make_pair
#define pii pair<int, int>
#define pll pair<ll, ll>
#define VT vector
#define VA valarray
#define pb push_back
#define SZ(a) ((int)a.size())
#define all(a) (a).begin(), (a).end()
#define TP template <class o>
#define TPP template <typename t1, typename t2>
#define rep(i, a, b) for (int i = a, i##_ = b; i <= i##_; i++)
#define REP(i, a, b) for (int i = b, i##_ = a; i >= i##_; i--)
#define FOR(i, n) rep(i, 1, n)
#define debug(x) cerr << #x << ' ' << '=' << ' ' << x << endl
using namespace std;
typedef long double db;
typedef long double ld;
typedef unsigned ui;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 i128;
typedef unsigned __int128 u128;

TPP istream &operator>>(istream &cin, pair<t1, t2> &a) {return cin >> a.first >> a.second; }
TP istream &operator>>(istream &cin, VT<o> &a) {for(o &i: a) cin >> i; return cin; }
TP istream &operator>>(istream &cin, VA<o> &a) {for(o &i: a) cin >> i; return cin;}
TP void qr(o& x) {cin >> x;}
template <class o, class... O> void qr(o& x, O&... y) { qr(x), qr(y...); }
TP void pr1(o x) { cout << x << ' ';}
template <class o, class... O> void pr1(o x, O... y) { pr1(x), pr1(y...); }
TP void pr2(o x) { cout << x << endl;}
template <class o, class... O> void pr2(o x, O... y) { pr2(x), pr2(y...); }
TPP ostream& operator <<(ostream &cout, pair<t1, t2> &a) {
    return cout << a.first << ' ' << a.second;
}
TP ostream& operator <<(ostream &cout, VA<o> &a) {
    int n = SZ(a);  if(!n) return cout;
    cout << a[0];
    for(int i = 1; i < n; i++) cout << ' ' << a[i];
    return cout;
}
TP ostream& operator <<(ostream &cout, VT<o> &a) {
    int n = SZ(a);  if(!n) return cout;
    cout << a[0];
    for(int i = 1; i < n; i++) cout << ' ' << a[i];
    return cout;
}
TPP ostream& operator <<(ostream &cout, VT<pair<t1, t2>> &a) {
    for(auto i: a) cout << i << '\n';
    return cout;
}
void yes(bool v) {cout << (v ? "yes\n" : "no\n");}
void YES(bool v) {cout << (v ? "YES\n" : "NO\n");}
void Yes(bool v) {cout << (v ? "Yes\n" : "No\n");}
TP bool cmax(o& x, o y) { return (x < y ? x = y, 1 : 0); }
TP bool cmin(o& x, o y) { return (x > y ? x = y, 1 : 0); }
TP void order(VT<o> &a) { sort(all(a)); a.resize(unique(all(a)) - a.begin());}
TP int get_id(VT<o> &a, const o& val) {return lower_bound(all(a), val) - a.begin();}
TP void sort(o &v) {sort(all(v));}

const int N = 303;
pii x[N], y[N];

db dis(int i, int j) {
    db u = x[i].fi - y[j].fi, v = x[i].se - y[j].se;
    return sqrtl(u * u + v * v);
}

const db eps = (db)1e-12, INF = 1e8;
int n;
db W[N][N];
int mat[N];
db Lx[N], Ly[N], slack[N];
bool S[N], T[N];

inline void tension(db &a, const db b) {
    if(b < a) a = b;
}

inline bool match(int u) {
    S[u] = true;
    for(int v = 0; v < n; ++v) {
        if(T[v]) continue;
        db t = Lx[u] + Ly[v] - W[u][v];
        if(fabs(t) < eps) {
            T[v] = true;
            if(mat[v] == -1 || match(mat[v])) {
                mat[v] = u;
                return true;
            }
        }else tension(slack[v], t);
    }
    return false;
}

inline void update() {
    db d = INF;
    for(int i = 0; i < n; ++i)
        if(!T[i]) tension(d, slack[i]);
    for(int i = 0; i < n; ++i) {
        if(S[i]) Lx[i] -= d;
        if(T[i]) Ly[i] += d;
    }
}

inline void KM() {
    for(int i = 0; i < n; ++i) {
        Lx[i] = Ly[i] = 0; mat[i] = -1;
        for(int j = 0; j < n; ++j) Lx[i] = max(Lx[i], W[i][j]);
    }
    for(int i = 0; i < n; ++i) {
        fill(slack, slack + n, INF);
        while(true) {
            for(int j = 0; j < n; ++j) S[j] = T[j] = false;
            if(match(i)) break;
            else update();
        }
    }
}


int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(15);
    qr(n);
    rep(i, 0, n - 1) qr(x[i]);
    rep(i, 0, n - 1) qr(y[i]);
    rep(i, 0, n - 1) rep(j, 0, n - 1) W[i][j] = 20000 -dis(i, j);
    KM();
    if(count(mat, mat + n, -1)) cout << -1;
    else {
        VT<int> ans(n);
        rep(i, 0, n - 1) ans[mat[i]] = i + 1;
        cout << ans;
    }
    return 0;
}

Code2:

#include <bits/stdc++.h>
#define fi first
#define se second
#define mk make_pair
#define pii pair<int, int>
#define pll pair<ll, ll>
#define VT vector
#define VA valarray
#define pb push_back
#define SZ(a) ((int)a.size())
#define all(a) (a).begin(), (a).end()
#define TP template <class o>
#define TPP template <typename t1, typename t2>
#define rep(i, a, b) for (int i = a, i##_ = b; i <= i##_; i++)
#define REP(i, a, b) for (int i = b, i##_ = a; i >= i##_; i--)
#define FOR(i, n) rep(i, 1, n)
#define debug(x) cerr << #x << ' ' << '=' << ' ' << x << endl
#define db double
using namespace std;
TP void qr(o &x){cin>>x;}
TPP void qr(pair<t1, t2> &x) {qr(x.fi); qr(x.se);}
TP void pr1(o x) {cout << x << ' ';}

const int N = 300;
pii x[N], y[N];
int a[N], n;

db dis(int i, int j) {
    db u = x[i].fi - y[j].fi, v = x[i].se - y[j].se;
    return sqrtl(u * u + v * v);
}

int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(15);
    qr(n);
    rep(i, 0, n - 1) qr(x[i]);
    rep(i, 0, n - 1) qr(y[i]);
    rep(i, 0, n - 1) a[i] = i;
    random_shuffle(a, a + n);
    bool f;
    do {
        f = 0;
        rep(i, 0, n - 1) rep(j, i + 1, n - 1)
            if(dis(i, a[i]) + dis(j, a[j]) > dis(i, a[j]) + dis(j, a[i])) {
                f = 1;
                swap(a[i], a[j]);
            }
    } while(f);
    rep(i, 0, n - 1) pr1(a[i] + 1);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Infinite_Jerry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值