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]);
}