2023牛客寒假算法基础集训营3(8/11)

不断减损的时间

贪心,负数只会越除越大,所以只操作正偶数

AC代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin >> n;
    LL ans = 0;
    vector<int> a(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
        while (a[i] % 2 == 0 && a[i] > 0) {
            a[i] /= 2;
        }
        ans += a[i];
    }
    cout << ans << '\n';
    return 0;
}

勉强拼凑的记忆

首先贪心地考虑最大化矩形边长,那就是n/2,所以至少可以用n/2块来表示一个边长为n/2的正方形,那么假设答案为ans,而且还要尽可能多的使用边长为n/2的矩形,可以得到下图方案

根据矩形数量关系,这样可以得到一个公式:3*ans-2*(n/2)<=n,最终就是要求最大的整数ans

AC代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int T;
    cin >> T;
    while (T--) {
        LL n;
        cin >> n;
        if (n == 2) {
            cout << "-1\n";
            continue;
        }
        LL m = (n + 1) / 2;
        cout << (n + 2 * m) / 3 << '\n';
    }
    return 0;
}

忽远忽近的距离

构造题可以先全排列打表看一看10以下的一些规律,发现小于等于3的和7都没有方案,有时也可以从得出的所有合理方案数里发现容易代码实现的构造方法。这个题可以把每个点能取到的数的范围写出来,发现样例[3,4,1,2]以后每四个都可以连续构造出来,所以%4=0是能够构造的,再考虑%4=1,从n=5的合理方案里发现,可以4 5 1 2 3,这样去掉这个五个数以后,再次得到%4=0,因此也是可以构造的,再考虑%4=2,尝试手玩发现前面可以构造4 5 6 1 2 3,这样先三个大的再三个小的的形式,因此%4=2也可以构造,最后构造%4=3,这种情况可以由%4=1和%4=2共同实现,同时减去一个5和6的循环又是%4=0的情况,这样也能判别出%4=3,最小只能构造出n=11,所以n=7,n<=3无解

AC代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    cin >> n;
    if (n <= 3 || n == 7) {
        cout << "-1\n";
        return 0;
    }
    if (n % 4 == 0) {
        int l = 3, r = 1;
        int p = n / 4;
        for (int i = 0; i < p; i++) {
            cout << l << " " << l + 1 << " " << r << " " << r + 1 << " ";
            l += 4;
            r += 4;
        }
        cout << '\n';
    } else if (n % 4 == 1) {
        cout << "4 5 1 2 3 ";
        int l = 8, r = 6;
        int p = n / 4 - 1;
        for (int i = 0; i < p; i++) {
            cout << l << " " << l + 1 << " " << r << " " << r + 1 << " ";
            l += 4;
            r += 4;
        }
        cout << '\n';
    } else if (n % 4 == 2) {
        cout << "4 5 6 1 2 3 ";
        int l = 9, r = 7;
        int p = n / 4 - 1;
        for (int i = 0; i < p; i++) {
            cout << l << " " << l + 1 << " " << r << " " << r + 1 << " ";
            l += 4;
            r += 4;
        }
        cout << '\n';
    } else {
        cout << "4 5 1 2 3 9 10 11 6 7 8 ";
        int l = 14, r = 12;
        int p = n / 4 - 2;
        for (int i = 0; i < p; i++) {
            cout << l << " " << l + 1 << " " << r << " " << r + 1 << " ";
            l += 4;
            r += 4;
        }
        cout << '\n';
    }
    return 0;
}

宿命之间的对决

根据题意分析,如果当前数是一个奇数,那么无论减哪个因子后留给下一个人的只能是偶数,如果当前数是一个偶数,那么一定能减某个因子后留给下一个人的可以是奇数可以是偶数,那么最优的就是给下个人留个奇数,这样就会奇偶奇偶不断循环,那么奇数一定是后手赢,偶数一定是先手赢

AC代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    LL n;
    cin >> n;
    if (n % 2 == 0) {
        cout << "kou\n";
    } else {
        cout << "yukari\n";
    }
    return 0;
}

公平守望的灯塔

找一个整点C,使得ABC为等腰直角三角形,可知可以选定A和B的中点D使A或B绕其旋转90度得到新坐标,判断新坐标是否为整点即可,在计算几何中,可以把点看作是复数运算即点(x,y)可以看作x+yi,那么旋转角度p的话,就是(x+yi)*(cosp+isinp)=xcosp-ysinp+yicosp+xisinp,新坐标就是(xcosp-ysinp,ycosp+xsinp)(记住)因为这个公式是base原点的,只需要坐标系平移即可,同时为了避免计算中点出现浮点数误差,可以坐标轴都扩大两倍,最后判断坐标奇偶

AC代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
struct P {
    long long x, y;
    P operator + (const P& p) {
        return {x + p.x, y + p.y};
    }
    P operator - (const P& p) {
        return {x - p.x, y - p.y};
    }
    double dot(const P& p) const {
        return 1.0 * x * p.x + 1.0 * y * p.y;
    }
    double det(const P& p) const {
        return 1.0 * x * p.y - 1.0 * y * p.x;
    }
    double dist(const P& p) const {
        return sqrt(1.0 * (x - p.x) * (x - p.x) + 1.0 * (y - p.y) * (y - p.y));
    }
};
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    P a, b;
    cin >> a.x >> a.y >> b.x >> b.y;
    a.x <<= 1;
    a.y <<= 1;
    b.x <<= 1;
    b.y <<= 1;
    P mid, c;
    mid.x = (a.x + b.x) / 2;
    mid.y = (a.y + b.y) / 2;
    c.x = -(a.y - mid.y) + mid.x;
    c.y = (a.x - mid.x) + mid.y;
    if (c.x % 2 == 0 && c.y % 2 == 0) {
        cout << c.x / 2 << " " << c.y / 2 << '\n';
    } else {
        cout << "No Answer!\n";
    }
    return 0;
}

迎接终结的寂灭

输出

AC代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    string s;
    getline(cin, s);
    cout << "42\n";
    return 0;
}

严肃古板的秩序

看到数据范围,可知'?'最多12个,所有数都是不超过1e9的非负整数,那么可以算出如果每个'?'都暴力枚举三种情况的话,复杂度就是3的12次方,即531441,再看字符串长度,最多14个数,即126,无论从空间还是时间,暴力都是满足的,注意'#'的应用条件

AC代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    string s;
    cin >> s;
    int len = s.size();
    vector<LL> z;
    LL p = 0;
    for (int i = 0; i < len;) {
        LL now = 0;
        while (i < len && s[i] != '?' && s[i] != '=') {
            now = now * 10 + (s[i] - '0');
            i++;
        }
        if (i == len) {
            p = now;
            break;
        }
        if (s[i] == '?') {
            z.push_back(now);
            i++;
        } else if (s[i] == '=') {
            z.push_back(now);
            i++;
        }
    }
    len = z.size();
    if (len == 1) {
        if (z[0] == p) {
            cout << s << '\n';
        } else {
            cout << "-1\n";
        }
        return 0;
    }
    function<LL(LL, LL, LL)> qp = [&](LL a, LL b, LL mod) {
        LL res = 1;
        a %= mod;
        for (; b; b >>= 1, a = a * a % mod) {
            if (b & 1) {
                res = res * a % mod;
            }
        }
        return res;
    };
    string en = "";
    bool ok = false;
    function<void(LL, LL, string)> dfs = [&](LL a, int i, string ans) {
        if (i == len) {
            if (a == p) {
                en = ans;
                ok = true;
            }
            return;
        }
        if (ok) {
            return;
        }
        dfs(a + z[i], i + 1, ans + '+');
        dfs(a - z[i], i + 1, ans + '-');
        if (z[i] > 0 && a > 0) {
            dfs(qp(a, a, z[i]), i + 1, ans + '#');
        }
    };
    dfs(z[0], 1, "");
    if (ok) {
        int cnt = en.size();
        int len1 = s.size();
        for (int i = 0, j = 0; i < len1; i++) {
            if (s[i] == '?') {
                cout << en[j];
                j++;
            } else {
                cout << s[i];
            }
        }
        cout << '\n';
    } else {
        cout << "-1\n";
    }
    return 0;
}

灵魂碎片的收集

先讨论偶数的时候,因为题目数据保证当x为偶数,x-1或x-3至少一个是素数,所以当x-1为素数,可以构造(x-1)*(x-1),约数为1、x-1,当x-3为素数可以构造2*(x-3),约数为1、2、x-3,当x为奇数,考虑用最少的素数个数使得约数之和为x,假设两个素数p、q,那就要满足1+p+q=x,移项后得到p+q=x-1,这就是哥德巴赫猜想,即任一大于2的偶数都可以写成两个质数之和,所以只需要暴力找p和对应的q即可

AC代码:

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int N = 1000000;
bool vis[1000010];
int prime[100010], cnt;
void get_prime() {
    for (int i = 2; i <= N; i++) {
        if (vis[i] == false) {
            prime[++cnt] = i;
        }
        for (int j = 1; j <= cnt && i * prime[j] <= N; j++) {
            vis[i * prime[j]] = true;
            if (i % prime[j] == 0) {
                break;
            }
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    get_prime();
    int T;
    cin >> T;
    while (T--) {
        int n;
        cin >> n;
        if (n == 1) {
            cout << "2\n";
            continue;
        }
        if (n == 3) {
            cout << "4\n";
            continue;
        }
        if (n == 5) {
            cout << "-1\n";
            continue;
        }
        if (n == 7) {
            cout << "8\n";
            continue;
        }
        if (n % 2 == 0) {
            int m = n - 1;
            if (!vis[m]) {
                cout << 1LL * m * m << '\n';
            } else {
                cout << 2 * (n - 3) << '\n';
            }
        } else {
            for (int i = 2;; i++) {
                if (!vis[i] && !vis[n - i - 1]) {
                    cout << 1LL * i * (n - i - 1) << '\n';
                    break;
                }
            }
        }
    }
    return 0;
}

构造+思维+数学场,我是菜鸡

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值