TypeDB Forces 2023 (Div. 1 + Div. 2, Rated, Prizes!)(A~E)

A. Exponential Equation

给出一个数n,给出一组x和y满足,若不存在满足情况的一组x和y,输出-1。

思路:一般这样的题向特殊情况思考。两数一个1,一个n/2即可满足,但是此时n必须为偶数;样例中奇数都是-1,则大胆猜测奇数输出-1即可。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
#define INF 0x3f3f3f3f
const int N = 2e5 + 5;
int t, 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;
        if(n & 1)
            std::cout << -1 << '\n';
        else
            std::cout << 1 << ' ' << n / 2 << '\n';
     }
    return 0;
}

B. Number Factorization

给出一个数n,可以将它分解成如题的一串数字相乘,得到两个序列a和p,求分解后每个a[i] * p[i]和的最大值,底数根据唯一分解定理所有因子的幂次必须都是1。

思路:因为是加法,所以每个底数越大越好,所以可以将n质因数分解,贪心计算每个数的值,相加即可。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N = 2e5 + 5;
int t, n, tot;
int prime[N], dif[N];
bool mark[N];

void oula() {
    for(int i = 2; i <= N; i ++) {
        if(!mark[i])
            prime[++ tot] = i;
        for(int j = 1; j <= tot; j ++) {
            if(i * prime[j] > N)
                break;
            mark[i * prime[j]] = 1;
            if(i % prime[j] == 0)
                break;
        }
    }
}

struct node {
    int prime, cnt;
    bool operator < (const node & a) const {
        return cnt < a.cnt;
    }
};

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    std::cin >> t;
    oula();
    while(t --) {
        std::cin >> n;
        std::map<int, int> mp;
        for(int i = 1; i <= tot; i ++) {
            while(n % prime[i] == 0) {
                mp[prime[i]] ++;
                n /= prime[i];
            }
        }
        if(n != 1)
            mp[n] ++;
        std::vector<node> vec;
        for(auto [x, y] : mp) {
            node b = {x, y};
            vec.push_back(b);
        }
        vec.push_back({1, 0});
        std::sort(vec.begin(), vec.end());
        int len = vec.size();
        dif[0] = 1;
        for(int i = 1; i < len; i ++) {
            dif[i] = dif[i - 1] * vec[i].prime;
        }
        ll ans = 0;
        for(int i = len - 1; i >= 1; i --) {
            vec[i].cnt -= vec[i - 1].cnt;
            ans += vec[i].cnt * (dif[len - 1] / dif[i - 1]);
        }
        std::cout << ans << '\n';
     }
    return 0;
}

C. Remove the Bracket

给出一个数组a,将从a[2] ~ a[n - 1]每一个分解为x[i] + y[i] = a[i],且(x[i] - s) * (y[i] - s) >= 0,求F的最小值。

思路:对于每一个a[i]来说,分解成的x[i]和y[i]仅在y[i - 1] * x[i] + y[i] * x[i + 1]这一部分中使用,可以换算成y[i - 1] * x[i] + (a[i] - x[i)] * x[i + 1],这样就是一个关于x[i]的一元一次函数,在极值处取得最小值,对于a[i] >= s,x[i]可以取到a[i] - s ~ s;反之,则取到0 ~ a[i]之间。设置f[i][4]表示前i个数的分解,4表示上一个数使得y[i]取值分别为0,s,a[i] - s,s,然后进行转移。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N = 2e5 + 5;
int t, n, s;
ll a[N];
ll f[N][4];

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    std::cin >> t;
    while(t --) {
        std::cin >> n >> s;
        for(int i = 1; i <= n; i ++) {
            std::cin >> a[i];
        }
        for(int i = 0; i <= n; i ++) {
            f[i][0] = f[i][1] = f[i][2] = f[i][3] = 1e18;
        }
        f[1][3] = 0;
        for(int i = 2; i <= n; i ++) {
            ll val1[4] = {0, s, a[i - 1] - s, a[i - 1]};
            ll val2[4] = {0, s, a[i] - s, a[i]};
            for(int j = 0; j <= 3; j ++) {
                for(int k = 0; k <= 3; k ++) {
                    if(i != n) {
                        if(a[i] > s && (k == 0 || k == 3)) continue;
                        if(a[i] < s && (k == 1 || k == 2)) continue;
                    }
                    f[i][k] = std::min(f[i][k], f[i - 1][j] + val1[j] * (a[i] - val2[k]));
                }
            }
        }
        std::cout << f[n][0] << '\n';
     }
    return 0;
}

os:DP好差。。。

D. Game on Axis

给出一个长为n的数组a,从1点开始,如果当前位置在[1, n]之间,那就可以跳到i + a[i]位置,否则游戏结束。在开始之前,我们可以选择一个x和一个y,将a[x]修改为y,使得有限次的跳转后,游戏结束。求不同(x, y)组数,使得修改后的数组满足条件。

思路:思路来自严格鸽

关于n + 1 和2 * n + 1的解释:

n + 1:在主干路上的可以一步跳出去,共有n + 1种方法;

2 * n + 1:不在主干路上的,可以任意赋值,共有2 * n + 1种方法。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
#define INF 0x3f3f3f3f
#define int long long
const int N = 2e5 + 5;
int t, n;
int a[N], dis[N];
bool vis1[N], vis2[N];

int DFS1(int u) {
    if(u < 1 || u > n) return 0;
    if(vis1[u]) return dis[u];
    vis1[u] = 1;
    return dis[u] = DFS1(u + a[u]) + 1;
}

int DFS2(int u) {
    if(u < 1 || u > n) return 0;
    if(vis1[u] || vis2[u]) return dis[u];
    vis2[u] = 1;
    return dis[u] = DFS2(u + a[u]);
}

signed 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 ++) {
            std::cin >> a[i];
        }
        for(int i = 1; i <= n; i ++) {
             vis1[i] = vis2[i] = 0, dis[i] = INF;
        }
        DFS1(1);
        for(int i = 2; i <= n; i ++) {
            DFS2(i);
        }
        std::vector<int> vec;
        for(int i = 1; i <= n; i ++) {
            if(dis[i] < INF) vec.push_back(dis[i]);
        }
        std::sort(vec.begin(), vec.end());
        int ans = 0;
        for(int i = 1; i <= n; i ++) {
            if(vis1[i]) {
                ans += n + 1;
                int next = lower_bound(vec.begin(), vec.end(), dis[i]) - vec.begin();
                ans += next;
            }
            else if(dis[1] < INF)
                ans += 2 * n + 1;
        }
        std::cout << ans << '\n';
    }
    return 0;
}

E. The Harmonization of XOR

给出一个permutat,长度为n,不重不漏的构造k组,每一组的异或和是x,给出构造方案,或者判断不存在方案。

思路:首先要满足所有数的异或和和k个x异或和相等,否则直接no;然后构造一个x,统计可以贡献x最高位数字的个数,不能少于k;若前两条都满足,则x为一组,再两两配对组成k - 2组,剩下的为一组。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
#define INF 0x3f3f3f3f
const int N = 2e5 + 5;
int t, n, k, x;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    std::cin >> t;
    while(t --) {
        std::cin >> n >> k >> x;
        int sum = (k % 2 ? x : 0);
        for(int i = 1; i <= n; i ++) {
            sum ^= i;
        }
        int tot = 0;
        for(int i = 1; i <= n; i ++) {
            if((x & i) > x / 2)
                tot ++;
        }
        if(sum != 0 || tot < k) {
            std::cout << "NO" << '\n';
            continue;
        }
        std::cout << "YES" << '\n';
        if(k == 1) {
            std::cout << n << ' ';
            for(int i = 1; i <= n; i ++) {
                std::cout << i << ' ';
            }
            std::cout << '\n';
        }
        else {
            int cnt = 0;
            std::set<int> ss;
            for(int i = 1; i <= n; i ++) {
                ss.insert(i);
            }
            if(ss.count(x)) {
                std::cout << 1 << ' ' << x << '\n';
                cnt ++;
                ss.erase(x);
            }
            for(int i = 1; i <= n; i ++) {
                if(!ss.count(i) || !ss.count(i ^ x)) continue;
                if(cnt == k - 1) break;
                cnt ++;
                std::cout << 2 << ' ' << i << ' ' << (i ^ x) << '\n';
                ss.erase(i);
                ss.erase(i ^ x);
            }
            std::cout << ss.size() << ' ';
            for(auto i : ss)
                std::cout << i << ' ';
            std::cout << '\n';
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值