AtCoder Beginner Contest 247

AtCoder Beginner Contest 247

A - Move Right

右移一位,直接模拟。

void solve() {
    string s;
    cin >> s;
    s.pop_back();
    s = "0" + s;
    cout << s << endl;
}

B - Unique Nicknames

map 统计一下即可。

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
using ll = long long;
const int maxn = 2e3 + 5;
string s[maxn], t[maxn];
map<string, int> mp;
void solve() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        cin >> s[i] >> t[i];
        mp[s[i]]++, mp[t[i]]++;
        if (s[i] == t[i])
            mp[s[i]]--;
    }
    int ans = 1;
    for (int i = 1; i <= n; ++i) {
        if (mp[s[i]] > 1 && mp[t[i]] > 1)
            ans = 0;
    }
    cout << (ans ? "Yes" : "No") << endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}

C - 1 2 1 3 1 2 1

简单递归。

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
using ll = long long;
const int maxn = 2e5 + 5;
void dfs(int n) {
    if (n <= 0)
        return;
    dfs(n - 1);
    cout << n << ' ';
    dfs(n - 1);
}
void solve() {
    int n;
    cin >> n;
    dfs(n);
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}

D - Cylinder

由于数很多,用一个 pair 表示一段相同的数,然后双端队列模拟两种操作。

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
using ll = long long;
const int maxn = 2e5 + 5;
void solve() {
    ll n, op, x, c;
    cin >> n;
    deque<pair<ll,ll>> q;
    for (int i = 1; i <= n; ++i) {
        cin >> op;
        if (op == 1) {
            cin >> x >> c;
            q.push_back({c, x});
        } else {
            cin >> c;
            ll ans = 0;
            while(!q.empty()) {
                auto p = q.front();
                q.pop_front();
                if (c > p.first) {
                    ans += p.first * p.second;
                    c -= p.first;
                } else {
                    ans += c * p.second;
                    p.first -= c;
                    q.push_front(p);
                    break;
                }
            }
            cout << ans << endl;
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}

E - Max Min

比赛的时候写的 ST 表上二分,预处理出区间最大和最小值,枚举左端点,二分右端点的范围,然后计算贡献,细节有点多。

更好的做法是用类似状压 dp 的方式统计以每个位置作为右端点产生的贡献,这样复杂度是 O ( n ) O(n) O(n) 的,并且更好写。

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
using ll = long long;
const int logn = 20;
const int maxn = 2e5 + 5;
int a[maxn];
int mx[maxn][logn], mn[maxn][logn], lg2[maxn + 1];
void init(int n) {
    lg2[1] = 0;
    for (int i = 2; i <= n; i++)
        lg2[i] = lg2[i / 2] + 1;
}
void work(int n, int *a) {
    for (int i = 1; i <= n; ++i) {
        mx[i][0] = a[i];
        mn[i][0] = a[i];
    }
    for (int j = 1; j <= logn; j++)
        for (int i = 1; i + (1 << j) - 1 <= n; i++) {
            mx[i][j] = max(mx[i][j - 1], mx[i + (1 << (j - 1))][j - 1]);
            mn[i][j] = min(mn[i][j - 1], mn[i + (1 << (j - 1))][j - 1]);
        }
}
int qmax(int &l, int &r) {
    int k = lg2[r - l + 1];
    return max(mx[l][k], mx[r - (1 << k) + 1][k]);
}
int qmin(int &l, int &r) {
    int k = lg2[r - l + 1];
    return min(mn[l][k], mn[r - (1 << k) + 1][k]);
}
void solve() {
    int n, x, y;
    cin >> n >> x >> y;
    for (int i = 1; i <= n; ++i) {
        cin >> a[i];
    }
    init(n);
    work(n, a);
    ll ans = 0;
    for (int i = 1; i <= n; ++i) {
        int l = i, r = n, L = i - 1, R = n + 1;
        while (l <= r) {
            int mid = (l + r) >> 1;
            if (qmax(i, mid) < x || qmin(i, mid) > y) {
                L = mid, l = mid + 1;
            } else {
                r = mid - 1;
            }
        }
        l = i, r = n;
        while (l <= r) {
            int mid = (l + r) >> 1;
            if (qmax(i, mid) > x || qmin(i, mid) < y) {
                R = mid, r = mid - 1;
            } else {
                l = mid + 1;
            }
        }
        if (L + 1 < R) {
            ans += R - L - 1;
        }
    }
    cout << ans << endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}

F - Cards

如果对 ( a i , b i ) (a_i,b_i) (ai,bi) 连边,容易发现最后会形成若干个环。显然总的方案数就是每个环的方案数之积,所以只需要搞清楚一个环的情况就好了。不妨从最简单的情况开始研究,如果是一个链,一条边上的两个点至少取一个,那么显然有 d p [ i ] = d p [ i − 1 ] + d p [ i − 2 ] dp[i]=dp[i-1]+dp[i-2] dp[i]=dp[i1]+dp[i2],对应最后一个取或不取。在环上取最后一个会影响两边的点,所以有 f [ i ] = d p [ i − 1 ] + d p [ i − 3 ] f[i]=dp[i-1]+dp[i-3] f[i]=dp[i1]+dp[i3],这就是一个环的方案数了。

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
using ll = long long;
const ll mod = 998244353;
const int maxn = 2e5 + 5;
int a[maxn], b[maxn];
ll f[maxn], g[maxn];
namespace dsu {
int fa[maxn], sz[maxn];
void init(int n) {
    iota(fa, fa + n + 1, 0);
    fill(sz, sz + n + 1, 1);
}
int find(int x) { 
    return fa[x] == x ? fa[x] : (fa[x] = find(fa[x])); 
}
bool merge(int x, int y) {
    x = find(x), y = find(y);
    if (x == y)
        return false;
    if (sz[x] < sz[y])
        swap(x, y);
    fa[y] = x, sz[x] += sz[y];
    return true;
}
}; // namespace dsu
void solve() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    for (int i = 1; i <= n; ++i)
        cin >> b[i];
    dsu::init(n);
    for (int i = 1; i <= n; ++i) {
        int x = dsu::find(a[i]);
        int y = dsu::find(b[i]);
        dsu::merge(x, y);
    }
    f[1] = 2, f[2] = 3, f[3] = 5;
    g[1] = 1, g[2] = 3, g[3] = 4;
    for (int i = 4; i <= n; ++i) {
        f[i] = (f[i - 1] + f[i - 2]) % mod;
        g[i] = (f[i - 1] + f[i - 3]) % mod;
    }
    ll ans = 1;
    for (int i = 1; i <= n; ++i) {
        int fa = dsu::find(i);
        if (fa == i) {
            ans = (ans * g[dsu::sz[i]]) % mod;
        }
    }
    cout << ans << endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}

G - Dream Team

经典费用流问题。超级源点 S S S 向每个 a a a 权值连流量为 1 1 1,费用为 0 0 0 的边,每个 b b b 权值向超级汇点 T T T 连流量为 1 1 1,费用为 0 0 0 的边,对于每个人 { a i , b i , c i } \lbrace a_i,b_i,c_i \rbrace {ai,bi,ci} a i a_i ai b i b_i bi 连流量为 1 1 1,费用为 − c i -c_i ci 的边,跑最小费用最大流即可。

#include<bits/stdc++.h>
#include <atcoder/all>
#define pb push_back
#define endl '\n'
using namespace std;
using ll = long long;
const int maxn = 1e5 + 5;
const ll inf = 1e12;
int a[maxn], b[maxn], c[maxn];
void solve() {
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i)
    	cin >> a[i] >> b[i] >> c[i];
    vector<ll> ans;
    for (int k = 1; k <= 150; ++k) {
    	atcoder::mcf_graph<int, ll> g(305);
    	int s = 301, t = 302;
    	for (int i = 1; i <= 150; ++i) {
        	g.add_edge(s, i, 1, 0);
        	g.add_edge(i + 150, t, 1, 0);
    	}
    	for (int i = 1; i <= n; ++i) {
       		g.add_edge(a[i], b[i] + 150, 1, inf - c[i]);
    	}
        auto now = g.flow(s, t, k);
        if (now.first < k) 
            break;
        else 
            ans.push_back(inf * k - now.second);
    }
    cout << ans.size() << endl;
    for (auto i : ans) 
        cout << i << endl;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T = 1;
    // cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}

Ex - Rearranging Problem

Rearranging Problem

太难了,不补了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值