2024/10/06 模拟赛总结

Bluemoon's Blog / 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;
}