10.22訓練賽
阿新 • • 發佈:2021-10-23
emmmmm, 這次比賽就3個小時, 前兩個小時都是我和聖元在打, 過了6題, 其實如果我們在前面沒有過多的討論I題的話罰時可能更少, 名次應該會更靠前,所以下次即使有有思路的難題還是放在簡單題後面好
D
當時我們大概討論出來了方案,f[i][j]表示前i個人, 第二排有j個人的方案數(顯然j <= i - j), 但我在寫的時候有幾個誤區:
1 不應該去列舉人, 而是列舉身高, 身高相同的人是等效的, 最後乘以階乘即可
2 顯然f[i][j]更新的時候, 需要加上上一種情況一個區間內的方案數, 那不如在開一個數組做字首和, O(1)求答案
細節還是挺多的, 還需要好好思考
程式碼
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 998244353; const int N = 5e3 + 10; template < typename T > inline void read(T &x) { x = 0; T ff = 1, ch = getchar(); while (!isdigit(ch)) { if (ch == '-') ff = -1; ch = getchar(); } while (isdigit(ch)) { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); } x *= ff; } int n, a[N], jc[N], b[N], f[N][N], g[N][N]; inline void pre() { jc[0] = 1; for (int i = 1; i <= n; ++i) jc[i] = (ll )jc[i - 1] * i % mod; } int main() { read(n); pre(); for (int i = 1; i <= n; ++i) { read(a[i]); ++b[a[i]]; } int u = 0; f[0][0] = 1, g[0][0] = 1; for (int i = 1; i <= n; ++i) { if (b[i]) { int v = u + b[i]; for (int j = 0; j <= v / 2; ++j) { int r = min(u / 2, j); int l = max(0, j - b[i]); if (l) f[v][j] = (g[u][r] - g[u][l - 1] + mod) % mod; else f[v][j] = g[u][r]; } g[v][0] = f[v][0]; for (int j = 1; j <= v / 2; ++j) g[v][j] = (g[v][j - 1] + f[v][j]) % mod; u = v; } } ll ans = f[n][n / 2]; for (int i = 1; i <= n; ++i) ans = ans * (ll) jc[b[i]] % mod; cout << ans << endl; return 0; }
J
在比賽中A掉的題, 假如Alive選的總和為A(可正可負),那麼原式就是|A|-|sum - A|, 那我們就想怎麼把絕對值去掉, 那就要討論sum和A的關係, 計算的A的最大值與sum比較,但是, 賽後我竟然把自己hack了, 或許人資料比較水, 上題解吧:
如果sum是負數的話把所有的數全部取負即可, 錯解就不說了, 這資料。。。
程式碼
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod = 998244353; const int N = 5e3 + 10; template < typename T > inline void read(T &x) { x = 0; T ff = 1, ch = getchar(); while (!isdigit(ch)) { if (ch == '-') ff = -1; ch = getchar(); } while (isdigit(ch)) { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); } x *= ff; } ll n, k = 1, a[N]; ll sum = 0, s1 = 0, s2; int main() { read(n); for (int i = 1; i <= n; ++i) read(a[i]); sort(a + 1, a + n + 1); for (int i = n; i >= 1; --i) { if (k == 1) s1 += a[i]; if (i & 1) s2 += a[i]; sum += a[i]; k ^= 1; } if (sum < 0) sum = -sum, s1 = -s2; cout << abs(s1) - abs(sum - s1); return 0; }
H
emmmmmm, 賽場上寫一個玄學演算法一直RE, 不理解。 考場上我傻掉了, 直接兩兩比較了, 但是, 一個車如果相撞, 肯定先和旁邊的車撞呀, 所以, 每個車考慮它的鄰居即可, 當然, 是編號不相等的鄰居, 由題意得, 我們可以二分答案, 每次都以當前的位置排序, 判斷相對位置是否發生變化, 當然, 也有很多細節, 比如0和1也是一個相對位置, 最後還要檢驗是否無解, 還是挺難調的。。。。
點選檢視程式碼
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef long long ll;
const int mod = 998244353;
const int N = 1e6 + 10;
template < typename T > inline void read(T &x) {
x = 0; T ff = 1, ch = getchar();
while (!isdigit(ch)) {
if (ch == '-') ff = -1;
ch = getchar();
}
while (isdigit(ch)) {
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
x *= ff;
}
int n, k;
struct node {
int p, v, t;
int id, pre;
}a[N], b[N];
inline bool cmp(node x, node y) {
return x.p < y.p;
}
inline bool check(int t) {
for (int i = 1; i <= n; ++i)
b[i] = a[i], b[i].p = a[i].p + a[i].v * t;
sort(b + 1, b + n + 1, cmp);
for (int i = 1; i <= n; ++i) {
if (b[i].t == b[i - 1].t) continue;
if (b[i].p == b[i - 1].p) return true;
if (b[i].pre != b[i - 1].id) return true;
}
return false;
}
signed main() {
read(n), read(k);
for (int i = 1; i <= n; ++i)
read(a[i].p), read(a[i].v), read(a[i].t);
sort(a + 1, a + n + 1, cmp);
for (int i = 1; i <= n; ++i) {
if (a[i].t == a[i - 1].t) {
a[i].id = a[i - 1].id;
a[i].pre = a[i - 1].pre;
} else {
a[i].id = a[i - 1].id + 1;
a[i].pre = a[i - 1].id;
} }
int l = 0, r = 2e9;
while (l < r) {
ll mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
if (!check(r)) puts("-1");
else cout << l - 1 << endl;
return 0;
}