ABC212

本期开始题目变为8道,100+200+300+400 * 2+500 * 2+600的模式。
F和G两个500分题均有难度,洛谷评分蓝

C - Min Difference

枚举 a i a_i ai b b b数组中二分,在结果中求最小值。这里写的有点冗余了,lower_bound查找的是大于等于target的位置。

#include <cstring>
#include <climits>
#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>

using namespace std;
typedef pair<int, int> pii;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef vector<int> vi;

char s[5];
int n, m;
int a[200020];
int b[200020];

 
int main() {
    //freopen("in.txt", "r", stdin);
    scanf("%d%d", &n, &m);
    for(int i = 0; i < n; ++ i) 
        scanf("%d", &a[i]);
    for(int i = 0; i < m; ++ i) {
        scanf("%d", &b[i]);
    } 
    sort(a, a + n);
    sort(b, b + m);
    ll ans = ll(1e18);
    for(int i = 0; i < n; ++ i){
        int j = lower_bound(b, b + m, a[i]) - b;
        if(j < m) {
            ll temp = abs(b[j + 1] - a[i]);
            ans = min(ans, temp);
        }
        if (j > 0) {
            ll temp = abs(b[j - 1] - a[i]);
            ans = min(ans, temp);
        }
        ll temp = abs(b[j] - a[i]);
        ans = min(ans, temp);
    }
    printf("%lld\n", ans);
    return 0;
}

D - Querying Multiset

堆的灵活运用,维护一个最小堆,并维护整体加的值。

/*
 * @Author: C.D.
 * @Date: 2024-02-23 11:20:19
 * @LastEditors: C.D.
 * @LastEditTime: 2024-02-27 16:29:53
 * @FilePath: \atcoder\atcoder.cpp
 *
 * Copyright (c) 2024 by C.D./tongwoo.cn, All Rights Reserved.
 */

#include <iostream>
#include <string>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <unordered_map>
#include <algorithm>
#define LT(x) (x * 2)
#define RT(x) (x * 2 + 1)

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;

int n;
ll add;
priority_queue<ll, vector<ll>, greater<ll>> qu;


int main(){
    //freopen("in.txt", "r", stdin);
    scanf("%d", &n);
    for(int i = 0; i < n; ++ i) {
        int op;
        scanf("%d", &op);
        if(op == 1) {
            ll x;
            scanf("%lld", &x);
            qu.push(x - add);
        } else if (op == 2) {
            ll x;
            scanf("%lld", &x);
            add += x;
        } else {
            ll frt = qu.top();
            qu.pop();
            printf("%lld\n", frt + add);
        }
    }
    return 0;
}

E - Safety Journey

DP
本题的边构成反图 G G G,即有 M M M条边是未连通的。在做的时候只需要减去这些边即可。
f ( i , j ) f(i,j) f(i,j) i i i步后,走到点 j j j的方法数。显然有
f ( i , j ) = ∑ e ( j , k ) ∈ G f ( i − 1 , k ) f(i,j)=\sum_{e(j,k) \isin G} f(i-1,k) f(i,j)=e(j,k)Gf(i1,k)
即点 j , k j,k j,k相连通
但这个 k k k数量非常大,接近 O ( N ) O(N) O(N),不能直接加起来。所以反过来考虑那些 e ( j , k ) ∉ G e(j,k) \notin G e(j,k)/G的,从总数中减去 f ( i − 1 , k ) f(i-1,k) f(i1,k)
f ( i , j ) = ∑ k = 1 n f ( i − 1 , k ) − ∑ e ( j , k ) ∉ G f ( i − 1 , k ) f(i,j)=\sum_{k=1}^{n} f(i-1,k) - \sum_{e(j,k) \notin G} f(i-1,k) f(i,j)=k=1nf(i1,k)e(j,k)/Gf(i1,k)

/*
 * @Author: C.D.
 * @Date: 2024-02-23 11:20:19
 * @LastEditors: C.D.
 * @LastEditTime: 2024-02-27 17:18:33
 * @FilePath: \atcoder\atcoder.cpp
 *
 * Copyright (c) 2024 by C.D./tongwoo.cn, All Rights Reserved.
 */

#include <iostream>
#include <string>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <unordered_map>
#include <algorithm>
#define LT(x) (x * 2)
#define RT(x) (x * 2 + 1)

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;

ll dp[5005][5005];
vi g[5005];
int n, m, k;
ll mod = 998244353;


void bfs() {
    dp[0][0] = 1ll;
    ll s = 1ll;
    for(int i = 1; i <= k; ++ i) {
        ll temp = 0;
        for(int u = 0; u < n; ++ u) {
            dp[i][u] = (s + mod - dp[i - 1][u]) % mod;
            for(int v: g[u]) {
                dp[i][u] = (dp[i][u] + mod - dp[i - 1][v]) % mod;
            }
            temp = (temp + dp[i][u]) % mod;
        }
        s = temp;
    }
    printf("%lld\n", dp[k][0] % mod);
}


int main(){
    //freopen("in.txt", "r", stdin);
    scanf("%d%d%d", &n, &m, &k);
    
    for(int i = 0; i < m; ++ i) {
        int u, v;
        scanf("%d%d", &u, &v);
        u--, v--;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    bfs();
    return 0;
}

F - Greedy Takahashi

在有向无环图中建立倍增链,跳表的思想
d p [ i ] [ j ] dp[i][j] dp[i][j]代表index为 i i i的边在 2 j 2^j 2j次模拟操作后新边的index
set中使用lower_bound 记录 d p [ i ] [ 0 ] dp[i][0] dp[i][0],然后倍增查询位置
具体见代码

/*
 * @Author: C.D.
 * @Date: 2024-02-23 11:20:19
 * @LastEditors: C.D.
 * @LastEditTime: 2024-02-29 14:57:49
 * @FilePath: \atcoder\atcoder.cpp
 *
 * Copyright (c) 2024 by C.D./tongwoo.cn, All Rights Reserved.
 */

#include <iostream>
#include <string>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <unordered_map>
#include <algorithm>
#define LT(x) (x * 2)
#define RT(x) (x * 2 + 1)

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;

const int N = 100020;

int n, m, q;
struct Edge {
    int u, v, s, t;
};
Edge e[N];
set<pii> ss[N];
int f[N][18];


int main(){
    //freopen("in.txt", "r", stdin);
    scanf("%d%d%d", &n, &m, &q);
    for(int i = 1; i <= m; ++ i) {
        int u, v, s, t; 
        scanf("%d%d%d%d", &u, &v, &s, &t);
        Edge edge({u, v, s, t});
        e[i] = edge;
        ss[u].insert({s, i});
    }
    for (int i = 1; i <= m; ++ i) {
        int v = e[i].v, t = e[i].t;
        auto it = ss[v].lower_bound(pii({t, 0}));
        if (it != ss[v].end()) {
            f[i][0] = it->second;
        }
    }
    for(int j = 1; j <= 17; ++ j) {
        for(int i = 1; i <= m; ++ i) {
            f[i][j] = f[f[i][j - 1]][j - 1];
        }
    }
    while(q --) {
        int x, y, z;
        scanf("%d%d%d", &x, &y, &z);
        auto it = ss[y].lower_bound(pii(x, 0));
        if(it == ss[y].end() || e[it->second].s >= z) {
            printf("%d\n", y);
        } else {
            int idx = it->second;
            for(int j = 17; j >= 0; -- j) {
                if(f[idx][j] && e[f[idx][j]].s < z) {
                    idx = f[idx][j];
                }
            }
            if(e[idx].t >= z) {
                printf("%d %d\n", e[idx].u, e[idx].v);
            } else {
                printf("%d\n", e[idx].v);
            }
        }
    }
    return 0;
}

G - Power Pair

预备知识:
数论阶
欧拉函数
以及欧拉函数和数论阶之间的关系

手模一下可以列出算式:
1 + ∑ d φ ( d ) ∗ d 1+\sum_{d} \varphi(d)*d 1+dφ(d)d
其中 φ ( x ) \varphi(x) φ(x)为欧拉函数, d d d n − 1 n-1 n1的因数
然后数据范围不大,直接算欧拉函数就好了

/*
 * @Author: C.D.
 * @Date: 2024-02-23 11:20:19
 * @LastEditors: C.D.
 * @LastEditTime: 2024-02-29 17:26:28
 * @FilePath: \atcoder\atcoder.cpp
 *
 * Copyright (c) 2024 by C.D./tongwoo.cn, All Rights Reserved.
 */

#include <iostream>
#include <string>
#include <cstring>
#include <climits>
#include <cstdlib>
#include <cmath>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <unordered_map>
#include <algorithm>
#define LT(x) (x * 2)
#define RT(x) (x * 2 + 1)

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;


ll n;
ll mod = 998244353;


ll phi(ll x) {
    ll ans = x;
    for (ll i = 2; i * i <= x; ++ i) {
        if(x % i == 0) {
            ans = ans / i * (i - 1);
            while(x % i == 0) 
                x /= i;
        }
    }
    if(x > 1) {
        ans = ans / x * (x - 1);
    }
    return ans % mod;
}


int main(){
    //freopen("in.txt", "r", stdin);
    scanf("%lld", &n);
    ll p = n - 1;
    ll ans = 1;
    for(ll i = 1; i * i <= p; ++ i) {
        if(p % i == 0) {
            ans = (ans + phi(i) * i % mod) % mod;
            if (i * i != p) {
                ll t = p / i % mod;
                ans = (ans + phi(p / i) * t % mod) % mod;
            }
        }
    }
    printf("%lld\n", ans);
    return 0;
}
  • 16
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值