2024“钉耙编程”中国大学生算法设计超级联赛(3)
死亡之组#
如果
否则:
,只需检验是否有 ,因为我们能同时选最大最小值。 ,此时不能选 了,剩下的位置必须留给 ,检查是否 。
code
#include<bits/stdc++.h>
#define eb emplace_back
#define ep emplace
using namespace std;
using ll = long long;
constexpr int N = 1e5 + 5;
int n, L, D, a[N];
void solve() {
cin >> n >> L >> D;
for(int i = 1; i <= n; ++ i) {
cin >> a[i];
}
int x = a[1];
sort(a + 1, a + n + 1);
int p = lower_bound(a + 1, a + n + 1, L) - a - 1;
int y = (x < L) ? a[n] : x;
if(p >= 3 && y - a[1] > D) {
cout << "Yes\n";
}
else {
cout << "No\n";
}
}
int main() {
cin.tie(0)->sync_with_stdio(0);
int T;
cin >> T;
while(T --) {
solve();
}
return 0;
}
深度自同构#
设
森林中的每棵树必须形态相同,因此有
树可以当做再
时间复杂度
code
#include<bits/stdc++.h>
using namespace std;
constexpr int N = 1e6 + 5, P = 998244353;
int n, f[N] = {1}, g[N];
int main() {
cin.tie(0)->sync_with_stdio(0);
cin >> n;
for(int i = 1; i <= n; ++ i) {
f[i] = (f[i - 1] + g[i - 1]) % P;
for(int j = i * 2; j <= n; j += i) {
g[j] = (g[j] + f[i]) % P;
}
}
for(int i = 1; i <= n; ++ i) {
cout << (f[i] + g[i]) % P << ' ';
}
return 0;
}
单峰数列#
线段树裸题。
对于
对于操作
code
#include<bits/stdc++.h>
#define eb emplace_back
#define ep emplace
using namespace std;
using ll = long long;
constexpr int N = 1e5 + 5;
int n, m;
struct Node {
int same, up, dw;
ll l, r, add;
void pushup(const Node &a, const Node &b) {
l = a.l, r = b.r;
same = (a.same && b.same && a.l == b.l);
up = (a.up && b.up && a.r < b.l);
dw = (a.dw && b.dw && a.r > b.l);
}
void addtag(ll v) {
l += v, r += v, add += v;
}
} t[N << 2];
#define ls x << 1
#define rs ls | 1
void pushup(int x) {
t[x].pushup(t[ls], t[rs]);
}
void pushdown(int x) {
if(t[x].add) {
t[ls].addtag(t[x].add), t[rs].addtag(t[x].add);
t[x].add = 0;
}
}
void build(int x = 1, int l = 1, int r = n) {
if(l == r) {
int v; cin >> v;
t[x] = {1, 1, 1, v, v};
return;
}
int mid = l + r >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
pushup(x);
}
void add(int L, int R, int v, int x = 1, int l = 1, int r = n) {
if(L <= l && r <= R) {
t[x].addtag(v);
return;
}
pushdown(x);
int mid = l + r >> 1;
if(L <= mid) add(L, R, v, ls, l, mid);
if(R > mid) add(L, R, v, rs, mid + 1, r);
pushup(x);
}
Node query(int L, int R, int x = 1, int l = 1, int r = n) {
if(L <= l && r <= R) return t[x];
pushdown(x);
int mid = l + r >> 1;
if(R <= mid) return query(L, R, ls, l, mid);
if(L > mid) return query(L, R, rs, mid + 1, r);
Node ret;
ret.pushup(query(L, R, ls, l, mid), query(L, R, rs, mid + 1, r));
return ret;
}
int main() {
cin.tie(0)->sync_with_stdio(0);
cin >> n, build();
cin >> m;
while(m --) {
int o, l, r; cin >> o >> l >> r;
if(o == 1) {
int v; cin >> v;
add(l, r, v);
continue;
}
int c = 0;
if(o != 5) {
Node x = query(l, r);
if(o == 2) c = x.same;
if(o == 3) c = x.up;
if(o == 4) c = x.dw;
}
else {
int tl = l, tr = r;
while(tl < tr) {
int mid = tl + tr + 1 >> 1;
(query(l, mid).up) ? tl = mid : tr = mid - 1;
}
if(tl == r || tl == l) c = 0;
else c = query(tl, r).dw;
}
cout << c << '\n';
}
return 0;
}
抓拍#
手玩一下,
(我也不会严格证明,反正枚举几种情况就是凹的)
同理
code
#include<bits/stdc++.h>
#define eb emplace_back
#define ep emplace
using namespace std;
using ll = long long;
constexpr int N = 2e5 + 5;
int n;
struct Node {
ll x, y; char o;
} a[N];
istream& operator >> (istream &in, Node &o) {
in >> o.x >> o.y >> o.o;
return in;
}
ll calc(int t) {
ll mxx = -1e18, mix = 1e18, mxy = -1e18, miy = 1e18;
for(int i = 1; i <= n; ++ i) {
auto [x, y, o] = a[i];
if(o == 'N') y += t;
if(o == 'S') y -= t;
if(o == 'E') x += t;
if(o == 'W') x -= t;
mxx = max(mxx, x), mix = min(mix, x);
mxy = max(mxy, y), miy = min(miy, y);
}
return 2 * (mxx - mix + mxy - miy);
}
int main() {
cin.tie(0)->sync_with_stdio(0);
cin >> n;
for(int i = 1; i <= n; ++ i) {
cin >> a[i];
}
int l = 0, r = 2e9;
while(l < r) {
int lmid = l + (r - l) / 3;
int rmid = r - (r - l) / 3;
if(calc(rmid) >= calc(lmid)) r = rmid - 1;
else l = lmid + 1;
}
cout << min(calc(l), calc(r));
return 0;
}
比特跳跃#
考虑哪些跳跃操作是有用的(为方便表示,用
如果从
但如果
直接的想法是
但是这样空间和时间都不允许。
考虑优化连边过程(下图),每个点只与相差一位的点之间连边,新增边数降到

code
#include<bits/stdc++.h>
#define eb emplace_back
#define ep emplace
using namespace std;
using ll = long long;
void solve() {
int n, m, k, tot; cin >> n >> m >> k;
tot = 2 * n;
vector g(tot + 1, vector<pair<int, ll>>{});
for(int i = 1; i <= m; ++ i) {
int x, y, z; cin >> x >> y >> z;
g[x].eb(y, z);
g[y].eb(x, z);
}
for(int i = 2; i <= n; ++ i) {
g[1].eb(i, ll(i | 1) * k);
g[i].eb(i + n, 0), g[i + n].eb(i, (ll)k * i);
}
for(int i = 2; i <= n; ++ i) {
for(int j = 0; j < 20; ++ j) {
if(i >> j & 1) {
int k = i ^ (1 << j);
if(!k) continue;
g[k + n].eb(i + n, 0);
}
}
}
vector<int> v(tot + 1);
vector<ll> d(tot + 1, 1e18);
priority_queue<pair<ll, int>> q;
q.ep(d[1] = 0, 1);
while(!q.empty()) {
int x = q.top().second;
q.pop();
if(v[x]) continue;
v[x] = 1;
for(auto [y, z] : g[x]) {
if(d[y] > d[x] + z) {
d[y] = d[x] + z;
q.ep(-d[y], y);
}
}
}
for(int i = 2; i <= n; ++ i) cout << d[i] << " \n"[i == n];
}
int main() {
cin.tie(0)->sync_with_stdio(0);
int T;
cin >> T;
while(T --) {
solve();
}
return 0;
}
旅行#
游走#
游戏#
记初始差值为
设在一轮中使
记
构造多项式
把
也就是
具体的,设
移项,
答案为
code
#include<bits/stdc++.h>
#define eb emplace_back
#define ep emplace
using namespace std;
using ll = long long;
constexpr int N = 3e6 + 5, V = 1e6;
constexpr int P = 998244353, tot = 1 << 21;
ll qpow(ll a, ll b = P - 2) {
ll c = 1;
while(b) {
if(b & 1) c = c * a % P;
b >>= 1;
a = a * a % P;
}
return c;
}
int n, t, rev[N], inv[10000005];
ll a[N], b[N], g[2];
ll c2(ll x) {return x * (x - 1) / 2 % P;}
void fft(ll *a, bool o = 1) {
for(int i = 0; i < tot; ++ i) {
if(i < rev[i]) {
swap(a[i], a[rev[i]]);
}
}
for(int mid = 1; mid < tot; mid *= 2) {
ll g1 = qpow(3, (P - 1) / (mid * 2));
if(!o) {
g1 = qpow(g1);
}
for(int i = 0; i < tot; i += mid * 2) {
ll gk = 1;
for(int j = 0; j < mid; ++ j, gk = gk * g1 % P) {
ll x = a[i + j], y = a[i + j + mid];
a[i + j] = (x + gk * y) % P;
a[i + j + mid] = (x - gk * y) % P;
}
}
}
if(o) return;
ll iv = qpow(tot);
for(int i = 0; i < tot; ++ i) a[i] = a[i] * iv % P;
}
int main() {
cin.tie(0)->sync_with_stdio(0);
cin >> n >> t;
for(int i = 1; i <= n; ++ i) {
int x; cin >> x;
++ a[x], ++ b[V - x];
}
ll s = 0;
for(int i = 1; i <= V; ++ i) s = (s + c2(a[i])) % P;
for(int i = 0; i < tot; ++ i) {
rev[i] = (rev[i / 2] / 2) | ((i & 1) << 20);
}
fft(a), fft(b);
for(int i = 0; i < tot; ++ i) a[i] = a[i] * b[i] % P;
fft(a, 0);
a[0] = s;
for(int i = 1; i < V; ++ i) a[i] = a[i + V];
ll im = qpow(c2(n));
ll p1 = (n - 2) * im % P, p0 = (1 - 2 * p1) % P;
g[0] = qpow(p1, t);
g[1] = t * p0 % P * qpow(p1, t - 1) % P;
inv[1] = 1;
for(int i = 2; i <= t; ++ i) {
inv[i] = -inv[P % i] * ll(P / i) % P;
}
ll ans = 0;
for(int i = 0; i <= 1; ++ i) {
int k = t - i;
if(k < V) ans = (ans + a[k] * g[i]) % P;
}
ll kk = p0 * qpow(p1) % P;
for(int i = 2; i <= t; ++ i) {
ll x = (2 * t - i + 2) * g[0] + (t - i + 1) * kk % P * g[1];
x = x % P * inv[i] % P;
int k = t - i;
if(k < V) ans = (ans + a[k] * x) % P;
g[0] = g[1], g[1] = x;
}
cout << (ans + P) % P;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】