2021牛客暑期多校训练营1

2021牛客暑期多校训练营1

A - Alice and Bob

由必败态去把其他状态推出来, 其实只记录必败态就行了

#include <bits/stdc++.h>
using namespace std;

int main() {
    vector<vector<bool>> f(5001, vector<bool>(5001));
    for (int i=0; i <= 5000;++ i)
        for (int j = 0; j <= i; ++j)
            if (!f[i][j])
                for (int k = 1; k + min(i,j) <= 5000; ++k)
                    for(int s = 0; s + min(i,j) <= 5000; s += k) {
                        int dx = i + k, dy = j + s;
                        if (max(dx, dy) <= 5000)
                            f[max(dx, dy)][min(dx, dy)]=1;
                        dx = i + s, dy = j + k;
                        if (max(dx, dy) <= 5000)
                            f[max(dx, dy)][min(dx, dy)]=1;
                    }
    int _;
    for (cin >> _; _; --_) {
        int n, m;
        cin >> n >> m;
        cout << (f[max(n, m)][min(m, n)] ? "Alice" : "Bob") << '\n';
    }
    return 0;
}

B - Ball Dropping

初中平面几何,做几条辅助线就出来了

看图找找相似三角形, 求求三角函数就算出来了

int main() {
    IOS;
    double r, a, b, h;
    cin >> r >> a >> b >> h;
    if (b - r * 2 >= 0)
        return cout << "Drop", 0;
    cout << "Stuck\n";
    double l = sqrt(h * h +sqr((a - b) / 2));
    double cur = (h * a / 2 - r * h * h / l) * 2  / (a - b);
    cout << precision(10) << h + r * ((a - b) / 2 / l) - cur;
    return 0;
}

D - Determine the Photo Position

int main() {
    int n, m;
    cin >> n >> m;
    vector<string> a(n);
    for (auto &i : a)
        cin >> i;

    string b;
    cin >> b;

    long long ans = 0;
    for (auto &s : a)
        for (int i = 0, j = 0; i < s.size(); i = ++j)
            if (s[i] == '0') {
                while (j < s.size() && s[j] == '0')
                    ++j;
                ans += max(0, (int)(j - i + 1 - b.size()));
            }
    cout << ans;
    return 0;
}

F - Find 3-friendly Integers

对于任意三个数,总有办法拼出3的倍数

暴力求100以内的个数即可

vector<int> sum(100);

void init() {
    for (int i = sum[0] = 1; i < 100; ++i) {
        bool f = 0;
        if (i % 10 % 3 == 0)
            f = 1;
        else if (i >= 10)
            if (i / 10 % 3 == 0)
                f = 1;
            else if ((i / 10 + i % 10) % 3 == 0)
               f = 1;
        sum[i] = sum[i - 1] + f;
    }
}

long long ask(long long n) {
    return n < 100 ? sum[n] : sum[99] + n - 99;
}

int main() {
    init();
    int _;
    for (cin >> _; _; --_) {
        long long l, r;
        cin >> l >> r;
        cout << ask(r) - ask(l - 1) << '\n';
    }
    return 0;
}

G - Game of Swapping Numbers

考虑把\(a_i, b_i\) 映射到数轴上, 则最后求的是n个线段的长度,

对于交换\(a_i, a_j\), 只有当线段\(i, j\) 不重合时才能有贡献, 且贡献为两个线段的距离的两倍(画个图就明白了)

\(max(a_i, b_j) < min(a_j, b_j)\) 交换后增加的贡献为 \((min(a_j, b_j) - max(a_i, b_j)) * 2\)

\(n = 2\)时, 只能交换\(1, 2\)

\(n > 2\)时,必定存在两个线段\(a_i - b_i > 0, a_j - b_j > 0\) \ \ 或 \(a_i - b_i < 0, a_j - b_j < 0\) \ \ 及这两个线段交换不会对答案产生影响, 及我们可以浪费交换次数

我们直接另\(mx_i = max(a_i, b_i), mi_i = min(a_i, b_i)\) 然后排序求差只算正的贡献即可

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int n, k;
    cin >> n >> k;
    vector<int> a(n), b(n);
    for (auto &i : a) cin >> i;
    for (auto &i : b) cin >> i;
    if (n == 2) {
        if (k & 1) swap(a[1], a[0]);
        cout << abs(a[0] - b[0]) + abs(a[1] - b[1]);
        return 0;
    }

    long long ans = 0;
    for (int i = 0; i < n; ++i) {
        ans += abs(a[i] - b[i]);
        if (a[i] < b[i]) swap(a[i], b[i]);
    }
    sort(a.begin(), a.end(), greater<int>());
    sort(b.begin(), b.end());
    for (int i = 0; i < min(k, n); ++i)
        ans += max(0, a[i] - b[i]);
    cout << ans;
    return 0;
}

H - Hash Function

首先发现模数不能使任意两个数的差的因子,但任意两数差就已经\(O(n^2)\)

考虑ftt,将求差变为多项式相乘

多项式相加都可以通过

\(x_i ± x_j, A^{x_i} \times A^{±x_j} = A^{x_i ± x_j}\)

这样就可以用ftt加速, 优化到\(nlogn\)

对指数加个偏移量就可以防止指数出现负数

const double PI = acos(-1.0);
struct Complex {
    double x, y;
    Complex(double _x = 0.0, double _y = 0.0) {
        x = _x;
        y = _y;
    }
    Complex operator-(const Complex &b) const {
        return Complex(x - b.x, y - b.y);
    }
    Complex operator+(const Complex &b) const {
        return Complex(x + b.x, y + b.y);
    }
    Complex operator*(const Complex &b) const {
        return Complex(x * b.x - y * b.y, x * b.y + y * b.x);
    }
};
/*
 * 进行 FFT 和 IFFT 前的反置变换
 * 位置 i 和 i 的二进制反转后的位置互换
 * len 必须为 2 的幂
 */
void change(Complex y[], int len) {
    vector<int> rev(len);
    for (int i = 0; i < len; ++i) {
        rev[i] = rev[i >> 1] >> 1;
        if (i & 1)  // 如果最后一位是 1,则翻转成 len/2
            rev[i] |= len >> 1;
    }
    for (int i = 0; i < len; ++i)
        if (i < rev[i])  // 保证每对数只翻转一次
            swap(y[i], y[rev[i]]);
}
/*
 * 做 FFT
 * len 必须是 2^k 形式
 * on == 1 时是 DFT,on == -1 时是 IDFT
 */
void fft(Complex y[], int len, int on) {
    change(y, len);
    for (int h = 2; h <= len; h <<= 1) {
        Complex wn(cos(2 * PI / h), sin(on * 2 * PI / h));
        for (int j = 0; j < len; j += h) {
            Complex w(1, 0);
            for (int k = j; k < j + h / 2; ++k) {
                Complex u = y[k], t = w * y[k + h / 2];
                y[k] = u + t;
                y[k + h / 2] = u - t;
                //模长相乘,辅角相加,模长为1相乘不变,相当于辅角增加了2 * PI / h
                w = w * wn;
            }
        }
    }
    if (on == -1)
        for (int i = 0; i < len; ++i)
            y[i].x /= len;
}
 
const int N = 5e5 + 5;
Complex x1[N << 2], x2[N << 2], x3[N << 2];
int n;
bool v[N];
 
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
 
    cin >> n;
    if (n == 1) return cout << 1, 0;
    int len = 1 << int(log2(1e6) + 1);
    for (int i = 0; i < len; ++i)
        x1[i] = x2[i] = Complex(0, 0);
    for (int i = 0; i < n; ++i) {
        int x; cin >> x;
        x1[x] = Complex(1, 0);
        x2[500000 - x] = Complex(1, 0);
    }
    fft(x1, len, 1);
    fft(x2, len, 1);
    for (int i = 0; i < len; ++i)
        x3[i] = x1[i] * x2[i];
    fft(x3, len, -1);
    for (int i = 1; i <= 500000; ++i)
        v[i] = int(x3[i + 500000].x + 0.5);
    for (int i = 2; i <= 500001; ++i) {
        int now = i;
        for (int j = i; j <= 500001; j += i)
            if (v[j]) now = -1;
        if (~now)
            return cout << now, 0;
    }
    return 0;
}

K - Knowledge Test about Match

纯靠猜, 瞎贪心

   for (cin >> _; _; --_) {
        cin >> n;
        VI cnt(n), a(n, -1);
        for (int i = 0; i < n; ++i) {
            int x; cin >> x;
            ++cnt[x];
        }
        for (int i = 0; i < n; ++i)
            for (int j = 0; j < n; ++j)
                if (~a[j]) continue;
                else if (j + i < n && cnt[j + i])
                    --cnt[j + i], a[j] = j + i;
                else if (j - i > -1 && cnt[j - i])
                    --cnt[j - i], a[j] = j - i;
        for (int i = 0; i < n; ++i) 
            cout << a[i] << char(" \n"[i == n - 1]);
    }
posted @ 2021-07-20 16:25  洛绫璃  阅读(57)  评论(0编辑  收藏  举报