2021牛客多校第一场

发布于 2021-07-17  778 次阅读


A.Alice and Bob

标签:博弈论,打表

题意:给定两堆石子(5e3),每次可以取一堆石子中k(k>=1),另一堆取k的整数倍个石子,不能取判负。

解法:根据sg函数打表发现规律,先手必负状态中每种石子数量只会出现一次,根据规律打第二个表,得到所有先手必负状态。

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

const int N = 10000 + 10;

bool c[N], a[N];
vector<pair<int, int>> ans;

bool check(int x, int y) { return x % y == 0 || y % x == 0; }

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n = 5000;
    for (int i = 2; i <= n; ++i) {
        if (1) {
            for (int j = 1; j <= n; ++j) {
                if (!c[j]) {
                    bool flag = true;
                    for (auto k : ans) {
                        if (i - k.first == 0 || i + j - k.second == 0 ||
                            i + j - k.first == 0 || i - k.second == 0 ||
                            (i - k.first > 0 && i + j - k.second > 0 &&
                             check(i - k.first, i + j - k.second)) ||
                            (i + j - k.first > 0 && i - k.second > 0 &&
                             check(i + j - k.first, i - k.second))) {
                            flag = false;
                            break;
                        }
                    }
                    if (flag) {
                        c[j] = true;
                        ans.push_back(make_pair(i, i + j));
                        if (i + j <= 5000)
                            cout << "s[" << i << "] = " << i + j << ";" << endl;
                        a[i] = a[i + 1] = a[i + j] = a[i + j + 1] = true;
                        break;
                    }
                }
            }
        }
    }
    return 0;
}

B.Ball Dropping

标签:计算几何

#include <cmath>
#include <iomanip>
#include <iostream>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    double r, a, b, h;
    cin >> r >> a >> b >> h;
    if (2 * r <= b) {
        cout << "Drop\n";
    } else {
        cout << "Stuck\n";
        double rad = atan((a - b) / 2.0 / h);
        double ans = r / sin(rad) - b / 2.0 / tan(rad);
        cout << fixed << setprecision(10) << ans << '\n';
    }
    return 0;
}

D.Determine the Photo Position

标签:模拟

题意:给定n*n(2000)的01矩阵,把1*m(2000)的矩阵放入给定矩阵中,求方案数

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

const int N = 2000 + 10;

char a[N][N];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n, m, ans = 0;
    cin >> n >> m;
    for (int i = 0; i < n; ++i) {
        int c = 0;
        for (int j = 0; j < n; ++j) {
            cin >> a[i][j];
            if (a[i][j] == '0') {
                c++;
            } else {
                if (c >= m)
                    ans += c - m + 1;
                c = 0;
            }
        }
        if (c >= m)
            ans += c - m + 1;
    }
    cout << ans << endl;
    return 0;
}

F.Find 3-friendly Integers

标签:模拟,思维

题意:T(10000)组数据,求[l, r](1e18)之间有多少个数满足存在子串为3的倍数

解法:发现当某个数大于等于100后,这个数必定满足条件,0-99可以模拟。

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

int a[100];

LL fun(LL n) {
    if (n <= 99)
        return a[n];
    else
        return a[99] + n - 99;
}

bool check(int n) {
    if (n < 10)
        return n % 3 == 0;
    if (n % 3 == 0)
        return true;
    if ((n / 10) % 3 == 0)
        return true;
    if ((n % 10) % 3 == 0)
        return true;
    return false;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin >> t;
    for (int i = 1; i <= 99; ++i) {
        a[i] = a[i - 1] + check(i);
    }
    while (t--) {
        LL l, r;
        cin >> l >> r;
        cout << fun(r) - fun(l - 1) << endl;
    }
    return 0;
}

H.Hash Function

标签:随机,模拟

题意:给定n(500000)个数,求最小的正整数使得所有的数对其取余结果不同。

解法:现场做法首先随机选择两个数,求出他们的差值,把差值的所有因数从答案集中删除,最后进行暴力判断。

赛后发现不用随机也能过,据说数据假了。

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

const int N = 500000 + 10;
const int RAND = 100000;

int a[N];
bool b[N];
bool c[N];

void fun(int n) {
    for (int i = 1; i <= sqrt(n); ++i) {
        if (n % i == 0) {
            b[i] = false;
            b[n / i] = false;
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;
    cin >> n;
    for (int i = 0; i < n; ++i) {
        cin >> a[i];
    }
    sort(a, a + n);
    for (int i = n; i <= a[n - 1] + 1; ++i) {
        b[i] = true;
    }
    srand(time(nullptr));
    auto t = clock();
    for (int i = 0; i < RAND; ++i) {
        auto t1 = clock();
        if ((t1 - t) / CLOCKS_PER_SEC >= 1)
            break;
        int l = rand() % n;
        int r = rand() % n;
        if (l > r)
            swap(l, r);
        fun(a[r] - a[l]);
    }
    for (int i = 0; i < n; i++)
        c[a[i]] = 1;
    for (int i = n; i <= a[n - 1] + 1; ++i) {
        if (!b[i])
            continue;
        int fl = 0;
        for (int j = 0; j < i; j++) {
            int cnt = 0;
            for (int k = 0; k <= 500000 / i && k * i + j <= 500000; k++)
                if (c[k * i + j] == 1)
                    cnt++;
            if (cnt > 1) {
                fl = 1;
                break;
            }
        }
        if (fl == 0) {
            cout << i << endl;
            break;
        }
    }
    return 0;
}

K.Knowledge Test about Match

标签:随机

题意:给定随机n(sum_n<4e5)个数,重新排序,使得与0~n-1差的开方和尽可能小,允许4%的误差

解法:首先排序,随机交换两个数,如果交换后更优则保留

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

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin >> t;
    while (t--) {
        srand(time(NULL));
        int n, x;
        cin >> n;
        set<int> a;
        vector<int> b;
        vector<int> c;
        for (int i = 0; i < n; ++i)
            a.insert(i);
        for (int i = 0; i < n; ++i) {
            cin >> x;
            if (a.count(x)) {
                a.erase(x);
            } else {
                b.push_back(x);
            }
        }
        for (auto i : a)
            c.push_back(i);
        sort(b.begin(), b.end());
        for (int j = 0; j < (n / 40000.0) * 10000000.0; ++j) {
            int l = rand() % b.size(), r = rand() % b.size();
            if (sqrt(abs(b[r] - c[l])) + sqrt(abs(b[l] - c[r])) -
                    sqrt(abs(b[l] - c[l])) - sqrt(abs(b[r] - c[r])) <
                0) {
                auto tmp = b[l];
                b[l] = b[r];
                b[r] = tmp;
            }
        }
        int p = 0;
        for (int i = 0; i < n; ++i) {
            if (a.count(i)) {
                cout << b[p++] << " ";
            } else {
                cout << i << " ";
            }
        }
        cout << endl;
    }
    return 0;
}