A. Gambling on Choosing Regionals
最差情况就是,强队都和你去一起。因此赛站越小,排名也一定越小。
然后只要动态实现出每个学校最强的若干只队伍就好了。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const int inf = INT_MAX / 2;
#define lowbit(x) (x & -x)
struct BinaryIndexedTree {
int n, sum;
vi b;
BinaryIndexedTree(int n) : n(n), b(n + 1) {
sum = 0;
}
void modify(int i, int y) {
sum += y;
for (; i <= n; i += lowbit(i))
b[i] += y;
return;
}
int calc(int i) {
int ans = 0;
for (; i; i -= lowbit(i))
ans += b[i];
return ans;
}
int upper(int x) {
return sum - calc(x);
}
};
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n, k;
cin >> n >> k;
int c = inf;
for (int i = 1, x; i <= k; i++)
cin >> x, c = min(c, x);
vector<pair<int, string>> team(n);
vi hw;
for (auto &[w, u]: team)
cin >> w >> u, hw.push_back(w);
sort(hw.begin(), hw.end());
hw.resize(unique(hw.begin(), hw.end()) - hw.begin());
for (auto &[w, u]: team)
w = lower_bound(hw.begin(), hw.end(), w) - hw.begin() + 1;
map<string, vector<pii>> cnt;
for (int i = 0; i < n; i++)
cnt[team[i].second].emplace_back(team[i].first, i);
BinaryIndexedTree bit(hw.size());
for (auto &[u, t]: cnt) {
sort(t.begin(), t.end(), greater<>());
for (int i = 0, N = min(c, (int) t.size()); i < N; i++)
bit.modify(t[i].first, 1);
}
vi res(n);
for (auto &[u, t]: cnt) {
for (int i = 0, N = min(c, (int) t.size()); i < N; i++)
bit.modify(t[i].first, -1);
for (int i = 0; i < t.size(); i++) {
res[t[i].second] = bit.upper(t[i].first) + min(i, c - 1) + 1;
}
for (int i = 0, N = min(c, (int) t.size()); i < N; i++)
bit.modify(t[i].first, 1);
}
for (int i: res) cout << i << "\n";
return 0;
}
E. Escape
你和机器人都不能停留在原地。其次\(d\)的限制并不是步数,而是移动半径。
假设你和机器人都可以停留在原地。那么我们可以预处理机器人到达某个点\(x\)的最早时间\(t[x]\)。
如果你到达\(x\)的最早时间为\(f\),则必须要保证\(f < t[x]\)。而对于\(t\),可以直接用多源bfs实现。
我们考虑不能停留的情况,机器人不能提前到达你的路上截停你,而是要在你路径上的某个点反复到达离开。如果\(f<t[x]\)则无所谓。如果\(f>t[x]\),则必须有\((f - t[x])\mod 2 = 0\)。然后要知道,机器人不唯一,到达某个点的路径也不唯一。因此我们要分奇偶求出到达每个点的最早时间。同理,在计算你的到达时间时也要分奇偶考虑。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const i32 inf = INT_MAX / 2;
const int mod = 998244353;
void solve() {
int n, m, d;
cin >> n >> m >> d;
vector<vi> e(n + 1);
for (int i = 1, x, y; i <= m; i++) {
cin >> x >> y;
e[x].push_back(y), e[y].push_back(x);
}
int k;
cin >> k;
vector t(2, vi(n + 1, inf));
queue<pii> q;
for (int i = 1, x; i <= k; i++) {
cin >> x;
t[0][x] = 0, q.emplace(x, 0);
}
vector vis(2, vi(n + 1));
while (not q.empty()) {
auto [x, tx] = q.front();
q.pop();
if (vis[tx & 1][x]) continue;
vis[tx & 1][x] = 1;
if (tx == d) continue;
for (int ty = tx + 1; auto y: e[x]) {
if (vis[ty & 1][y]) continue;
if (t[ty & 1][y] <= ty) continue;
t[ty & 1][y] = ty, q.emplace(y, ty);
}
}
q.emplace(1, 0);
vis = vector(2, vi(n + 1));
vector f(2, vi(n + 1, inf));
vector lst(2, vi(n + 1, -1));
f[0][1] = 0;
while (not q.empty()) {
auto [x, fx] = q.front();
q.pop();
if (vis[fx & 1][x]) continue;
vis[fx & 1][x] = 1;
for (int fy = fx + 1; auto y: e[x]) {
if (vis[fy & 1][y]) continue;
if (t[fy & 1][y] <= fy) continue;
if (f[fy & 1][y] <= fy) continue;
f[fy & 1][y] = fy, lst[fy & 1][y] = x;
q.emplace(y, fy);
}
}
int ret = min(f[0][n], f[1][n]);
if (ret == inf) {
cout << "-1\n";
return;
}
cout << ret << "\n";
vi p;
for (int x = n, y = ret & 1; x != -1; x = lst[y][x], y ^= 1)
p.push_back(x);
ranges::reverse(p);
for (auto i: p)
cout << i << " ";
cout << "\n";
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while (T--)
solve();
return 0;
}
F. Tourist
签到
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
i64 cnt = 1500;
for (int i = 1, x; i <= n; i++) {
cin >> x, cnt += x;
if (cnt >= 4000) {
cout << i << "\n";
return 0;
}
}
cout << -1;
return 0;
}
G. Game
平局的状态不影响结果。因此我们可以记Alice 获胜的概率是\(P_a = \frac{a_0}{a_0 + a_1}\),Bob 获胜的概率是\(P_b = \frac{a_1}{a_0 + a_1}\)。
我们可以利用一种类似更相减损术的方法求解。但是复杂度太高了。我们考虑归纳一下。
对于当前的状态\((x,y)\),有以下三种情况
- \(x = y\),此时Alice获胜的概率是\(P_a\)
- \(x < y\),此时Alice必须连续至少赢得$d = \left \lceil \frac{y - x }{x} \right \rceil $ 局,才有机会获胜,因此可以递归计算\((x , y - dy)\)
- \(x>y\),此时Bob必须连续至少赢得$d=\left \lceil \frac{x - y}{y} \right \rceil $ 局,才有机会获胜,因此可以递归计算\((x - dy, y)\)
这样的话,复杂度就和辗转相除法一样是\(O(\log n)\)
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const i32 inf = INT_MAX / 2;
const int mod = 998244353;
struct mint {
i64 x;
mint(int x = 0) : x(x) {}
int val() const {
return (x % mod + mod) % mod;
}
mint &operator=(int o) { return x = o, *this; }
mint &operator+=(mint o) { return (x += o.x) >= mod && (x -= mod), *this; }
mint &operator-=(mint o) { return (x -= o.x) < 0 && (x += mod), *this; }
mint &operator*=(mint o) { return x = (i64) x * o.x % mod, *this; }
mint &operator^=(int b) {
mint w = *this, ret(1);
for (; b; b >>= 1, w *= w) if (b & 1) ret *= w;
return x = ret.x, *this;
}
mint &operator/=(mint o) { return *this *= (o ^= (mod - 2)); }
friend mint operator+(mint a, mint b) { return a += b; }
friend mint operator-(mint a, mint b) { return a -= b; }
friend mint operator*(mint a, mint b) { return a *= b; }
friend mint operator/(mint a, mint b) { return a /= b; }
friend mint operator^(mint a, int b) { return a ^= b; }
};
void solve() {
int x, y, _;
cin >> x >> y;
mint a, b;
cin >> a.x >> b.x >> _;
mint pa = a / (a + b), pb = b / (a + b);
auto calc = [pa, pb](auto &&calc, int x, int y, mint p) -> mint {
if (x == y) return p * pa;
if (x < y) {
int d = (y - x + x - 1) / x;
return calc(calc, x, y - d * x, p * (pa ^ d));
} else {
int d = (x - y + y - 1) / y;
return p * (1 - (pb ^ d)) + calc(calc, x - d * y, y, p * (pb ^ d));
}
};
cout << calc(calc, x, y, mint(1)).val() << "\n";
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while (T--)
solve();
return 0;
}
I. Strange Binary
\(4\)的倍数无解,然后我们考虑先构造奇数,然后在加1即可
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const i32 inf = INT_MAX / 2;
const int mod = 998244353;
void solve() {
int n;
cin >> n;
if (n % 4 == 0) {
cout << "NO\n";
return;
}
bool ok = false;
if (n % 2 == 0) {
ok = true;
n--;
}
vi a(32, -1);
a[31] = 1, n /= 2;
for (int i = 0; i < 31; i++)
if (n >> i & 1) a[i] = 1;
if (ok) a[0] = 0;
cout << "YES";
for (int i = 0; i < 32; i++)
cout << " \n"[i % 8 == 0] << a[i];
cout << "\n";
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while (T--)
solve();
return 0;
}
J. Stacking of Goods
可以证明按照\(\frac{c_i}{w_i}\)排序一定最优,剩下的贪心就好了。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
vi w(n), c(n);
int res = 0;
for (int i = 0, v; i < n; i++) {
cin >> w[i] >> v >> c[i];
res += v;
}
vi p(n);
iota(p.begin(), p.end(), 0);
sort(p.begin(), p.end(), [&](const int &x, const int &y) -> bool {
return -c[y] * w[x] > -c[x] * w[y];
});
vi W(n);
for (int i = n - 2; i >= 0; i--)
W[p[i]] = W[p[i + 1]] + w[p[i + 1]];
for (auto i: p)
res -= c[i] * W[i];
cout << res;
return 0;
}
L. 502 Bad Gateway
其实可以猜到存在一个阈值\(x\),满足小于等于\(x\)时,不做额外的操作,大于\(x\)时不断的随机。
对于小于等于\(x\)的部分,期望次数就是
\[\frac{1}{T} + \frac{2}{T} + \frac{3}{T}\dots \frac{x}{T} \]然后我们考虑大于\(x\)的情况,大于的情况总共有\(T - x\)种,每一种的概率都是\(\frac{1}{T}\)。对于随机,随机到小于等于\(x\)的概率为\(\frac {x}{T}\),这就是一个简单的几何分布,因此期望就是\(\frac{T}{x}\)。当我们随机到小于等于\(x\)的情况下,还需要操作的期望是\(\frac{1}{x} + \frac{2}{x} + \frac{3}{x}\dots +\frac{x}{x}\)。因此大于\(x\)部分的期望就是
\[\frac{T-x}{T}(\frac{T}{x} + \frac{1}{x} + \frac{2}{x} + \frac{3}{x}\dots +\frac{x}{x}) \]因此总的期望此时就是
\[Ex = \frac{x^2(x+1) +(T-x)[2T+x(x+1)]}{2Tx} \]这个式子很遗憾不满足单调性。但是通过打表发现,当\(T\)取\(1,2,3\dots\)时,\(x\)的取值为
\[1,2,2,3,3,3,4,4,4,4,5,5,5,5,5,\dots \]#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using i128 = __int128;
#define int i64
using vi = vector<int>;
using pii = pair<int, int>;
const int inf = LLONG_MAX / 2;
using ldb = long double;
const ldb eps = 1e-12;
i128 gcd(i128 a, i128 b) {
return b ? gcd(b, a % b) : a;
}
ostream &operator<<(ostream &os, i128 x){
string s;
while(x > 0)
s += char(x % 10 + '0'), x /= 10;
reverse(s.begin(), s.end());
os << s;
return os;
}
struct Z {
i128 x, y;
Z() {}
void norm(){
i128 d = gcd(x, y);
x /= d, y /= d;
}
bool operator<(const Z &b) const{
return x * b.y < b.x * y;
}
Z &operator=(Z b) {
x = b.x, y = b.y;
return *this;
}
};
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int T;
cin >> T;
while(T --){
int n;
cin >> n;
auto calc =[&](int x ) -> Z{
Z ans;
ans.x = (i128)x * x *(x + 1) + (i128)(n - x) * ((i128)n * 2 + x * (x + 1));
ans.y = (i128)n * x * 2;
ans.norm();
return ans;
};
int l = 1 , r = n , ret = -1;
while(l <= r){
int mid = (l + r) / 2;
if(mid * (mid + 1) / 2 >= n) ret = mid, r = mid - 1;
else l = mid + 1;
}
auto res = calc(ret);
cout << res.x << " " << res.y << "\n";
}
return 0;
}
标签:i64,frac,Contest,int,return,Asia,II,using,mint
From: https://www.cnblogs.com/PHarr/p/18442957