QBXT2025S刷题 Day6
今天的题
今天还行 \(135pts,rk15\)。
T1
这道题我用的贪心,从头开始,如果遇到一个数 \(> r\),就把它模 \(r\)。
否则就把 \(i\sim i + k - 1\) 减去这个数。
使用差分做到 \(\mathcal{O}(n)\)。
No 的话判断是否有数 \(<\) \(0\),或者是否一个减的区间右端点超过 \(n\) 就行。
代码:
#include <iostream>
#define lowbit(x) x & (-x)
using std::cin;
using std::cout;
const int N = 3e5 + 10;
typedef long long ll;
ll n;
ll a[N];
ll cf[N];
ll sum[N];
void read(ll &x)
{
x = 0;
ll f = 1;
char c = getchar();
while (!isdigit(c))
{
if (c == '-')
f = -f;
c = getchar();
}
while (isdigit(c))
{
x = x * 10 + c - '0';
c = getchar();
}
x = x * f;
}
int main()
{
ll k;
ll r;
read(n);
read(k);
read(r);
for (int i = 1; i <= n; ++i)
{
read(a[i]);
cf[i] = a[i] - a[i - 1];
}
ll now = 0;
for (int i = 1; i <= n; ++i)
{
now += cf[i];
if (now < 0)
{
cout << "No" << '\n';
return 0;
}
if (!now)
continue;
if (now >= r)
{
cf[i + 1] += now / r * r;
now %= r;
}
if (!now)
continue;
if (i + k - 1 > n)
{
cout << "No" << '\n';
return 0;
}
cf[i] -= now;
cf[i + k] += now;
now = 0;
}
cout << "Yes" << '\n';
return 0;
}
T2
这道题是树形 \(\mathcal{DP}\),我们注意到如果一个点能和他的一个子树合并成为一个三叉,那么可以是以下四种情况。

然后我们的状态记录一下当前有 \(i\) 个链,\(j\) 个倒 "Y"。
这样,我们可以先让 \(i\) 个链三三匹配。
那么如果 \(j \geq i\%3\),那么这 \(i\) 个链就可以完全用掉。
我们看第一种情况,我们要留下一个链。
因此要满足 \(j\geq (i-1)\%3\)。
其他的情况同理。
再就是我们要把状态压缩一下。
我们注意到 \(i = 3\) 和 \(i = 0\) 是两种不同的状态,因为我们不能从 \(0\) 中取出两条链。
\(i = 4\) 同理。
因此我们状态要记录到 \(5\)。
\(j\) 要记录到 \(3\),这个很好看出来。
代码:
// ☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
// ░░░░░░░░░░░░░░░░░░░░░▄▄▄▄▄▄▄░░░░░░░░░░░░░░░░░░░░
// ░░░░░░░░░░░░░░░░░░░░░█▀▀▀▄░░▀▀▀▄▄░░░░░░░░░░░░░░░
// ░░░░░░░░░░░░░░░░░░░░░█▄▄▄░▀▀▄▄░░░▀▀▄░░░░░░░░░░░░
// ░░░░░░░░░░░░░░░░░░░░░░░░░▀▀▄▄░▀▄░░░░▀▄░░░░░░░░░░
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▀▄░▀▄░░░░▀▄░░░░░░░░
// ░░░░░░░░░░░░░░░░░▄▀▀▀▀▀▀▀▀▄░░░░▀▄░█░░░░▀▄░░░░░░░
// ░░░░░░░░░░░░░░░▄▀░░░░░░░░░░█░░░░░█░█░░░░▀▄░░░░░░
// ░░░░░░░░░░░░░▄▀░░░░░░░░░░░▄█░░░░░░█░█░░░░▀▄░░░░░
// ░░░░░░░░░░░▄▀░░░░░░░░░░░▄▀░█░░░░░░░█░█░░░░█░░░░░
// ░░░░░░░░░▄▀░░░░░░░░░░░░█░▄▀░░░░░░░░░█▀█░░░░█░░░░
// ░░░░░░░░█░░░░░░░░░░░░░░░▀▄░░░░░░░░░░▀▄█░░░░█░░░░
// ░░░░░░░░█▄░░░░░░░░▄▄░░░░░░▀▄░░░░░░░░░██░░░░█░░░░
// ░░░░░░░░█░▀▄░░░░▄▀░░▀▄░░░░░░▀▄░░░░░░░██░░░░█░░░░
// ░░░░░░░░░▀▄░▀▄▄▀░▄▀▀▄░▀▄░░░░░░▀▄░░░░░█░░░░░█░░░░
// ░░░░░░░░░░░▀▄█░▄▀░░░░▀▄░▀▄░░░░░░▀▄░░▄▀░░░░▄█░░░░
// ░░░░░░░░░░░░░▀▀░░░░░░░░▀▄░▀▄░░░░░░▀▄▀░░░░░██░░░░
// ░░░░░░░░░░▄▀▀▀▀▄░░░░░░░░░▀▄░▀▄░░░░░░░░░░░██░░░░░
// ░░░░░░▄▄▀▀░░░░░░█▄░░░░░░░░░▀▄░█░░░░░░░░░▄█▀░░░░░
// ░░░░▄▀░░░░░░░░░░░░▀▀▀▄▄▄▄▄▄▄▄▀░░░░░░░░░░▀█░░░░░░
// ░░░█░░░░░░░░░▄░░░░░░░░░░░░░░░░░░░░░░░░░░░░▀▄░░░░
// ░░█░░░░░░░░▄▀░▀█░░░░░░░░░░░░░░░░░░█▀▀█░░░░░░▀▄░░
// ░░█░░░░░░░▄▀▄▀▄░▀▀▀▀▄▄▄▄▄▄▄▄▄▄▄▀▀▀░▄▄░▀█░░░░░█░░
// ░░█▀▄▄▄▄▀▀░▄▀░░▀▄▄▄▄░░░░░░░░░░░▄▄▄▀░░▀▄░▀▄▄▄▀█░░
// ░░▀▄░░░░▄▄▀░░░░░░░░░▀▀▀▀▀▀▀▀▀▀▀░░░░░░░░▀▄░░░▄▀░░
// ░░░░▀▀▀▀░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▀▀▀░░░░
// ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
// ☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭☭
#include <iostream>
#include <vector>
#define int long long
using std::cin;
using std::cout;
const int N = 1e5 + 10;
typedef long long ll;
struct Edge
{
int to, w;
};
int now[8][6];
int son[N][6];
int dp[N][8][6];
std::vector<Edge> e[N];
void DP(int x, int father)
{
dp[x][0][0] = 0;
for (auto nxt : e[x])
{
int to = nxt.to;
int val = nxt.w;
if (to == father)
continue;
DP(to, x);
for (int i = 0; i <= 5; ++i)
{
for (int j = 0; j <= 3; ++j)
now[i][j] = -1e18 - 7;
}
for (int i = 0; i <= 5; ++i)
{
for (int j = 0; j <= 3; ++j)
{
now[i][j] = std::max(now[i][j], dp[x][i][j] + son[to][0]);
now[i][std::min(j + 1, 3ll)] = std::max(now[i][std::min(j + 1, 3ll)], dp[x][i][j] + val + std::max(son[to][2], son[to][3]));
now[i == 5 ? 3 : i + 1][j] = std::max(now[i == 5 ? 3 : i + 1][j], dp[x][i][j] + val + std::max(son[to][0], son[to][1]));
}
}
for (int i = 0; i <= 5; ++i)
{
for (int j = 0; j <= 3; ++j)
dp[x][i][j] = now[i][j];
}
}
for (int i = 0; i <= 5; ++i)
{
for (int j = i % 3; j <= 3; ++j)
son[x][0] = std::max(son[x][0], dp[x][i][j]);
}
for (int i = 0; i <= 4; ++i)
{
for (int j = i % 3; j <= 3; ++j)
son[x][1] = std::max(son[x][1], dp[x][i + 1][j]);
}
for (int i = 0; i <= 3; ++i)
{
for (int j = i % 3; j <= 3; ++j)
son[x][2] = std::max(son[x][2], dp[x][i + 2][j]);
}
for (int i = 0; i <= 5; ++i)
{
for (int j = i % 3; j <= 2; ++j)
son[x][3] = std::max(son[x][3], dp[x][i][j + 1]);
}
}
signed main()
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
for (int i = 1; i <= n; ++i)
e[i].clear();
for (int i = 1; i < n; ++i)
{
int u, v, w;
cin >> u >> v >> w;
e[u].push_back((Edge){v, w});
e[v].push_back((Edge){u, w});
}
for (int i = 1; i <= n; ++i)
{
for (int j = 0; j <= 5; ++j)
{
for (int k = 0; k <= 3; ++k)
{
dp[i][j][k] = -1e18 - 7;
son[i][k] = -1e18 - 7;
}
}
}
DP(1, 0);
cout << son[1][0] << '\n';
}
return 0;
}
T3
这道题我们可以对 \(e_i \geq \dfrac{E}{2}\) 和 \(e_i < \dfrac{E}{2}\) 进行两两分组。
如果都第一组里,就可以任意交换。
我们记录每一个第一组最左,最右可以走到哪。
我们发现这些形成的区间要么是完全包含,要么是不交。
因此这些形成了一个树形的结构。
我们直接使用类似树形 \(\mathcal{DP}\) 的方法做就行。
代码:
#include <iostream>
#include <vector>
#include <algorithm>
#define int long long
using std::cin;
using std::cout;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
struct Node
{
int min;
Node()
{
min = 2e9 + 7;
}
void init(int v)
{
min = v;
}
friend Node operator+(const Node &l, const Node &r)
{
Node ret;
ret.min = std::min(l.min, r.min);
return ret;
}
} z[N << 2];
int ans = 1;
int n, E;
int po;
int ee[N];
int l[N];
int r[N];
int e[N];
int sum[N];
std::vector<std::pair<int, int>> p;
#define root 1, n, 1
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
void build(int l, int r, int rt)
{
if (l == r)
{
z[rt].init(ee[l]);
return;
}
int mid = (l + r) >> 1;
build(lson);
build(rson);
z[rt] = z[rt << 1] + z[rt << 1 | 1];
}
int query1(int l, int r, int rt, int nowl, int nowr, int k)
{
if (z[rt].min > k || nowr < nowl)
return 0;
if (l == r)
return l;
int mid = (l + r) >> 1;
int now = 0;
if (nowr > mid)
now = query1(rson, nowl, nowr, k);
if (nowl <= mid && now == 0)
now = query1(lson, nowl, nowr, k);
return now;
}
int query2(int l, int r, int rt, int nowl, int nowr, int k)
{
if (z[rt].min > k || nowr < nowl)
return n + 1;
if (l == r)
return l;
int mid = (l + r) >> 1;
int now = n + 1;
if (nowl <= mid)
now = query2(lson, nowl, nowr, k);
if (nowr > mid && now == n + 1)
now = query2(rson, nowl, nowr, k);
return now;
}
int dfs()
{
int x = po++;
int nowsize = 1;
while (po < p.size() && p[po].second <= p[x].second)
nowsize += dfs();
ans = 1ll * ans * (nowsize + sum[p[x].second - 1] - sum[p[x].first]) % mod;
return nowsize;
}
signed main()
{
freopen("str.in", "r", stdin);
freopen("str.out", "w", stdout);
cin >> n >> E;
for (int i = 1; i <= n; ++i)
{
cin >> e[i];
ee[i] = (e[i] <= (E >> 1) ? e[i] : 2e9 + 7);
}
build(root);
for (int i = 1; i <= n; ++i)
{
if (e[i] > (E >> 1))
{
l[i] = query1(root, 1, i - 1, E - e[i]);
r[i] = query2(root, i + 1, n, E - e[i]);
sum[i] = sum[i - 1];
}
else
sum[i] = sum[i - 1] + 1;
}
for (int i = 1; i <= n; ++i)
{
if (e[i] > (E >> 1))
p.push_back({l[i], r[i]});
}
std::sort(p.begin(), p.end(), [&](const std::pair<int, int> &a, const std::pair<int, int> &b)
{ return (a.first != b.first ? a.first < b.first : a.second > b.second); });
sum[n + 1] = sum[n];
po = 0;
while (po < p.size())
dfs();
cout << ans << '\n';
return 0;
}
T4
不会

浙公网安备 33010602011771号