The 2022 ICPC Asia Xian Regional Contest

题目顺序大致按照难度排序。

F. Hotel

The 2022 ICPC Asia Xian Regional Contest_第1张图片

现在酒店中有单人间和双人间,价格分别是c1,c2,现在有n个队,每队三个人,性别分别用字母表示,当两个人性别相同且在同一个队时,他们可以住在双人间中。求最少需要多少钱使得n个队住下。

思路:直接模拟。

AC Code:

#include 

typedef long long ll;
const int N = 1e5 + 5;
ll n, c1, c2;
std::string s;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    std::cin >> n >> c1 >> c2;
    ll ans = 0;
    for(int i = 1; i <= n; i ++) {
        std::cin >> s;
        std::sort(s.begin(), s.end());
        if(s[0] == s[1] || s[1] == s[2]) {
            ans += std::min(c1, c2) + std::min(c1 * 2, c2);  
        }
        else
            ans += std::min(c1, c2) * 3;
    }
    std::cout << ans << '\n';
    return 0;
}

 J. Strange Sum

The 2022 ICPC Asia Xian Regional Contest_第2张图片

给出n个数的序列a,可以从中选择一些数字,但是如果选择了a[i],则要满足序列中所有长度为i的子串中最多有两个数被选到,现在求选择的数和最大是多少,注意,可以不选任何数。

思路:假设我们选择了三个数a[i]、a[j]和a[k],且k>j>i,那么在1~k区间内就会有三个数,不满足条件,可以得到最多选择两个数。排序贪心选择即可。

AC Code:

#include 

typedef long long ll;
const int N = 1e5 + 5;
int n;
int a[N];

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    std::cin >> n;
    for(int i = 1; i <= n; i ++) {
        std::cin >> a[i];
    }
    std::sort(a + 1, a + 1 + n, std::greater());
    std::cout << std::max({0, a[1], a[1] + a[2]}) << '\n';
    return 0;
}

C. Clone Ranran

The 2022 ICPC Asia Xian Regional Contest_第3张图片

有个人要准备c道题,他可以进行如下两种操作:花费a分钟克隆一个自己;花费b分钟准备一道题目。问准备c道题最少需要多长时间。

思路:最优选择一定是先尽可能快的克隆自己,然后最后一起花b分钟准备一道题,得到的计算式是a\times x + \left \lceil \frac{c}{2^{x}} \right \rceil \times b,x是克隆的次数。

AC Code:

#include 

typedef long long ll;
const int N = 1e5 + 5;
int t;
ll a, b, c;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    std::cin >> t;
    while(t --) {
        std::cin >> a >> b >> c;
        ll ans = 1e18;
        for(int i = 0; i <= 30; i ++) {
            ll res = 1 << i;
            res = (ll)(ceil(c * 1.0 / res));
            ans = std::min(ans, a * i + res * b);
        }
        std::cout << ans << '\n';
    }
    return 0;
}

 G. Perfect Word

The 2022 ICPC Asia Xian Regional Contest_第4张图片

给出n个字符串,对于一个字符串,若它的所有子串都出现在了这n个字符串中,则称这个字符串是good的,则最大的good串的长度是多少。

思路:可以从数据范围考虑起。若一个字符串能成为good字符串,且长度为x,那么它的x * (x + 1) / 2个子串都要出现,这样想good串长度最多是根下1e5级别,我们大约可以用350代替。然后考虑暴力,如果所有的串长度都是350,那一共最多有1e5 / 350个字符串,完全可以暴力,这样循环的时间复杂度是1e7级别,可以过。

AC Code:

#include 

typedef long long ll;
const int N = 1e5 + 5;
int n;
std::string s[N];
std::unordered_map mp;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    std::cin >> n;
    for(int i = 1; i <= n; i ++) {
        std::cin >> s[i];
        mp[s[i]] ++;
    }
    int ans = 0;
    for(int i = 1; i <= n; i ++) {
        int len = s[i].length();
        bool flag = true;
        for(int j = 0; j < len; j ++) {
            for(int k = 1; k <= len; k ++) {
                if(j + k - 1 >= len) continue;
                std::string ss = s[i].substr(j, k);
                if(!mp[ss]) {
                    flag = false;
                    break;
                }
            }
            if(!flag) break;
        }
        if(flag)
            ans = std::max(ans, (int)s[i].length());
    }
    std::cout << ans << '\n';
    return 0;
}

E. Find Maximum

The 2022 ICPC Asia Xian Regional Contest_第5张图片 给出函数f(x),回答t次询问,每次给出l和r,求区间[l, r]之间最大的f(x)是多少。

思路:f(x)的值可以联想到三进制,不过它是x的三进制加位数的和,那就直接贪心,使得三进制下每一位2的数量尽可能多。

AC Code:

#include 

typedef long long ll;
const int N = 1e5 + 5;
int t;
ll f[N];

std::vector get3(ll x) {
    std::vector vec;
    while(x) {
        int num = x % 3;
        vec.push_back(num);
        x /= 3;
    }
    reverse(vec.begin(), vec.end());
    return vec;
}

ll getans(ll x) {
    if(!x) return 1;
    else if(x % 3 == 0) return getans(x / 3) + 1;
    else return getans(x - 1) + 1;
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    std::cin >> t;
    while(t --) {
        ll l, r;
        std::cin >> l >> r;
        std::vector R = get3(r);
        ll ans = std::max(getans(l), getans(r));
        int n = R.size();
        for(int i = 0; i < n; i ++) {
            ll res = 0;
            if(R[i] == 0) continue;
            for(int j = 0; j < i; j ++) {
                res = res * 3 + R[j];
            }
            res = res * 3 + R[i] - 1;
            for(int j = i + 1; j < n; j ++) {
                res = res * 3 + 2;
            }
            if(res >= l)
                ans = std::max(ans, getans(res));
        }
        std::cout << ans << '\n';
    }
    return 0;
}

 L. Tree

The 2022 ICPC Asia Xian Regional Contest_第6张图片

定义节点u的subtree(u)是以u为根的子树中所有节点的集合,现在称集合S是good的当且仅当它满足至少一个条件:1、对于S中所有不同的u和v,满足u是vsubtree中的一点或反之;2、对于S中所有不同的u和v,他们两个没有父子树关系。现给出一棵树,问可以划分的good集合数最小是多少。

思路:官方题解:

The 2022 ICPC Asia Xian Regional Contest_第7张图片

 解释一下概念:链和反链是在简单有向无环图中定义的,在一条路径中出现的点,是在一条链上;不在一条路径上出现的点,即无法相互到达的点,是在一条反链上,形象的来说,在题目给定的树中,可以定义这棵树是以根节点为起始点的有向图,那么链就是在一条路径中的点,反链连接的就是若干叶子结点(也不一定都是叶子结点)。 

AC Code:

#include 

typedef long long ll;
const int N = 1e6 + 5;
int t, n;
int d[N], cnt[N], dep[N];
std::vector vec[N];

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    std::cin >> t;
    while(t --) {
        std::cin >> n;
        for(int i = 1; i <= n; i ++) {
            vec[i].clear();
            d[i] = cnt[i] = dep[i] = 0;
        }
        for(int i = 2; i <= n; i ++) {
            int u;
            std::cin >> u;
            d[u] ++;
            vec[i].push_back(u);
        }
        std::queue q;
        for(int i = 1; i <= n; i ++) {
            if(!d[i]) {
                q.push(i);
                dep[i] = 1;
            }
        }
        while(!q.empty()) {
            int now = q.front();
            q.pop();
            for(auto u : vec[now]) {
                dep[u] = dep[now] + 1;
                d[u] --;
                if(!d[u]) {
                    q.push(u);
                }
            }
        }
        for(int i = 1; i <= n; i ++) {
            cnt[dep[i]] ++;
        }
        int ans = 2e9;
        for(int i = 1; i <= n; i ++) {
            ans = std::min(ans, cnt[i] + i - 1);
        }
        std::cout << ans << '\n';
    }    
    return 0;
}

 气,感觉铜牌题看了题解也不难,但是赛时想不到www

B是网络流?没学,爬了

你可能感兴趣的:(补题专栏,c++,算法)