2024/10/06 模拟赛总结
\(100+70+0+0=170\),CD 暴力真写不了
#A.喷泉
圆和线段一定没有交点,所以最长距离一定在线段端点,直接比较即可。最短距离就是垂直线段长度
// BLuemoon_
#include <bits/stdc++.h>
using namespace std;
using DB = double;
struct P {
DB x, y;
DB operator^(const P &o) {
return sqrt((x - o.x) * (x - o.x) + (y - o.y) * (y - o.y));
}
};
struct L {
DB k, b;
};
int t;
P a, b, c;
DB r;
L S(P u, P v) {
if (u.x == v.x) {
return (L){3247.1508, u.x};
}
DB _k = (v.y - u.y) / (v.x - u.x), _b = u.y - _k * u.x;
return (L){_k, _b};
}
L H(L p, P x) {
if (p.k == 3247.1508) {
return (L){0, x.y};
}
if (p.k == 0) {
return (L){3247.1508, x.x};
}
L ret = (L){-1.0 / p.k, 0};
ret.b = x.y - x.x * ret.k;
return ret;
}
P R(L u, L v) {
if (v.k == 3247.1508) {
swap(u, v);
}
if (u.k == 3247.1508) {
return (P){u.b, v.b};
}
P ret = (P){(u.b - v.b) / (v.k - u.k), 0};
ret.y = ret.x * u.k + u.b;
return ret;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
freopen("fountain.in", "r", stdin), freopen("fountain.out", "w", stdout);
for (cin >> t; t; t--) {
cin >> a.x >> a.y >> b.x >> b.y >> c.x >> c.y >> r;
cout << fixed << setprecision(2) << (R(S(a, b), H(S(a, b), c)) ^ c) - r << ' ' << max(a ^ c, b ^ c) + r << '\n';
}
return 0;
}
#B.红绿灯
直接暴力优化,经过一定操作一些数会变成一样,所以经过一次操作之后就去重一次
为了继续剪枝,我们可以进行完每次操作进行完就求一次 \(\gcd\),如果当前值是 \(\gcd\) 的因数则不会修改,直接跳过即可
// BLuemoon_
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int kMaxN = 1e5 + 5;
int n, m, a[kMaxN][2], b[kMaxN][2], q, g = 1, cnt;
int Div(int x, int y) {
return (x / y) + (x % y != 0);
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
freopen("light.in", "r", stdin), freopen("light.out", "w", stdout);
cin >> n >> m, a[0][0] = n;
for (int i = 1; i <= n; i++) {
a[i][0] = b[i][0] = i;
}
for (int i = 1; i <= m; i++) {
cin >> q;
if (g % q) {
int cur = i & 1;
cnt += a[0][cur ^ 1], a[0][cur] = 0;
for (int j = 1; j <= a[0][cur ^ 1]; j++) {
a[j][cur ^ 1] = Div(a[j][cur ^ 1], q) * q;
}
for (int j = 1; j <= a[0][cur ^ 1]; j++) {
(j == 1 || a[j][cur ^ 1] != a[j - 1][cur ^ 1]) && (a[++a[0][cur]][cur] = a[j][cur ^ 1]);
b[a[0][cur]][cur] = b[j][cur ^ 1];
}
g = a[1][cur];
for (int j = 1; j <= a[0][cur]; j++) {
g = __gcd(g, a[j][cur]);
}
}
}
cnt += a[0][m & 1];
for (int i = 1, j = 0; i <= n; i++) {
for (; b[j][m & 1] < i; j++) {
}
cout << a[j][m & 1] << " \n"[i == n];
}
return 0;
}
#C.子集
注意到 \(F_{k}(S)=\displaystyle\sum_{T\subseteq S}F_{0}(T)\times k^{|S|-|T|}\)
令 \(F_{i,w}\) 表示 \(\Set{a_1,a_2,\dots,a_i}\) 的所有和为 \(w\) 的子集的贡献之和
当选了 \(a_i\) 时,\(|S|,|T|\) 都会 \(+1\),没有改变,否则 \(|S|\) 增加了 \(1\),\(|T|\) 不变,所以要乘上一个 \(k\)。
那么:\(F_{i,w}=F_{i-1,w-a_i}+k \times F_{i-1,w}\)
// BLuemoon_
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
const int kMaxN = 5e3 + 5;
const LL kP = 1e9 + 7;
int t, n, m, k;
LL dp[kMaxN][kMaxN], a[kMaxN];
int main() {
freopen("subset.in", "r", stdin), freopen("subset.out", "w", stdout);
for (cin >> t; t; t--, fill(dp[0], dp[n + 2], 0)) {
cin >> n >> m >> k, dp[0][0] = 1;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= m; j++) {
dp[i][j] = dp[i - 1][j] * k % kP;
(j - a[i] >= 0) && ((dp[i][j] += dp[i - 1][j - a[i]]) %= kP);
}
}
cout << dp[n][m] << '\n';
}
return 0;
}
#D.佛怒火莲
令 \(dp_i\) 为前 \(i\) 个位置已经选了的方案是否可行,可以存在 unsigned int
的每一位上
那么可以得到 \(dp_i=dp_{i-1}\,\text{or}\,((t\,\text{and}\,ok_{col_i})\,\text{lmv}\,(1\,\text{lmv}\,col_i))\)
// BLuemoon_
#include <bits/stdc++.h>
using namespace std;
const int kMaxN = 1e4 + 5;
struct P {
int u, v;
bool operator<(const P &o) const {
return v < o.v;
}
};
P a[kMaxN];
int t, n, k, typ, v[kMaxN], c[kMaxN], p, ans;
unsigned int q, dp[kMaxN];
mt19937 Rd(time(0) / 2 + 3247);
int Chk(int e) {
fill(dp, dp + kMaxN, 0), dp[0] = q = 1, p = 0;
for (int i = 1; i <= n; i++) {
for (; p < i - 1 && a[i].v - a[p + 1].v >= e; q |= dp[++p]) {
}
dp[i] = dp[i - 1] | ((q & v[c[a[i].u]]) << (1u << c[a[i].u]));
}
for (; p < n; q |= dp[++p]);
return q >> ((1u << k) - 1);
}
int main() {
freopen("fire.in", "r", stdin), freopen("fire.out", "w", stdout);
for (cin >> t; t; t--, ans = 0) {
cin >> n >> k >> typ;
for (int i = 1; i <= n; i++) {
cin >> a[i].u >> a[i].v;
}
sort(a + 1, a + n + 1), fill(v, v + kMaxN, 0);
for (int i = 0; i < k; i++) {
for (int j = 0; j < 1 << k; j++) {
!(j & (1u << i)) && (v[i] |= (1u << j));
}
}
for (int T = 150; T; T--) {
for (int i = 1; i <= n; i++) {
c[i] = Rd() % k;
}
int cur = -1;
for (int i = 1 << 20; i; i >>= 1) {
(Chk(cur + i) == 1) && (cur += i);
}
ans = max(ans, cur);
}
cout << ans << '\n';
}
return 0;
}