QBXT2025S刷题 Day1

今天的题目

\(rk17\)

T1

\(90pts\)
赛时树状数组写挂了。
发现没有特判第一个数是 \(0\)
我的思路是,\(cnt[x]\) 表示对于所有的 \(h[i] \geq x\) 可以构成多少个区间。
先离散化。
对于当前 \(h[i]\),若 \(h[i - 1] < h[i]\),则 \(h[i - 1] + 1\)\(h[i]\)\(cnt\) 会加一,因为 \(i\) 是新区间的开始。
\(h[i - 1] \geq h[i]\), 则不会有任何的贡献,因为如果 \(i\) 存在,那么 \(i - 1\) 也会存在,所以 \(i\) 不是新区间的开始。
这个直接在树状数组上差分。
还要特判 \(h[1] = 0\)
代码:

#include <iostream>
#include <vector>
#include <algorithm>
#include <cstdio>
#define lowbit(x) x & (-x)

using std::cin;
using std::cout;
const int N = 1e6 + 10;

int n;
int max_val;
int h[N];
int b[N];
int re[N];
int sum[N];
std::vector<int> v;

void add(int x, int val)
{
	for (; x <= max_val; x += lowbit(x))
		sum[x] += val;
}
int query(int x)
{
	int ret = 0;
	for (; x; x -= lowbit(x))
		ret += sum[x];
	return ret;
}
void read(int &x)
{
	x = 0;
	int 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 *= f;
}

int main()
{
	read(n);
	for (int i = 1; i <= n; ++i)
	{
		read(h[i]);
		v.push_back(h[i]);
	}
	std::sort(v.begin(), v.end());
	v.erase(std::unique(v.begin(), v.end()), v.end());
	for (int i = 1; i <= n; ++i)
	{
		b[i] = std::lower_bound(v.begin(), v.end(), h[i]) - v.begin() + 1;
		re[b[i]] = h[i];
	}
	for (int i = 1; i <= n; ++i)
		max_val = std::max(max_val, b[i]);
	if (h[1] > 0)
	{
		add(1, 1);
		if (b[1] + 1 <= max_val)
			add(b[1] + 1, -1);
	}
	for (int i = 2; i <= n; ++i)
	{
		if (b[i - 1] < b[i])
		{
			add(b[i - 1] + 1, 1);
			if (b[i] + 1 <= max_val)
				add(b[i] + 1, -1);
		}
	}
	int max = 0;
	for (int i = 1; i <= max_val; ++i)
	{
		int now = query(i);
		if (now > max)
			max = now;
	}
	cout << max << '\n';
	return 0;
}

T2

写了第一个分段。
这道题其实一眼数位 \(DP\)
\(\mathcal{AK\_Dream}\):这是一道简单题。
但是我不会。
先考虑 \(L = R\) 的情况。
\(dp[i][j]\) 表示,考虑到 \(i\),所有的后缀中,\(\%k\)\(j\) 的方案数。
\(dp[i + 1][(j * 10 + num[i]) \% k] += dp[i][j]\)
\(dp[i + 1][num[i] \% k] += dp[i][j]\)
同理,直接把这个转化一下就行了。
老师的代码:

#include <bits/stdc++.h>
#define N 50005
#define K 105
using namespace std;

const int mod = 1000000007;
inline int qmod(int x) { return x < mod ? x : x - mod; }
inline void qadd(int &x, int y) { (x += y) >= mod ? (x -= mod) : 0; }

char L[N], R[N];
int k, dp[2][N][K];
int tenc[N], upc[N];

int DP(char *T, int d, int sum, bool up, bool zero)
{
	int ans = 0;
	if (d < 0)
	{
		return sum == -2;
	}
	if (!zero && dp[up][d][sum + 2] != -1)
	{
		return dp[up][d][sum + 2];
	}
	int mx = up ? T[d] - '0' : 9;
	for (int i = 0; i <= mx; i++)
	{
		bool new_up = up && (i == mx), new_zero = zero && (i == 0);
		if (sum >= 0)
		{
			int new_sum = (sum * 10 + i) % k;
			if (new_sum == 0)
			{
				qadd(ans, DP(T, d - 1, -2, new_up, new_zero));
			}
			qadd(ans, DP(T, d - 1, new_sum, new_up, new_zero));
		}
		else if (sum == -1)
		{
			if (!new_zero)
			{
				qadd(ans, DP(T, d - 1, i % k, new_up, new_zero));
				if (i % k == 0)
				{
					qadd(ans, DP(T, d - 1, -2, new_up, new_zero));
				}
			}
			qadd(ans, DP(T, d - 1, -1, new_up, new_zero));
		}
		else if (sum == -2)
		{
			qadd(ans, DP(T, d - 1, -2, new_up, new_zero));
		}
	}
	if (!zero)
		dp[up][d][sum + 2] = ans;
	return ans;
}

int calc(char *T, int len)
{
	memset(dp, -1, sizeof(dp));

	int ans = DP(T, len - 1, -1, true, true);
	return ans;
}

void solve()
{
	scanf("%s %s %d", L, R, &k);
	int lenL = strlen(L), lenR = strlen(R);
	reverse(L, L + lenL);
	reverse(R, R + lenR);

	for (int i = 0; i < lenL; i++)
	{
		if (L[i] != '0')
		{
			L[i]--;
			break;
		}
		L[i] = '9';
	}
	if (L[lenL - 1] == '0')
		--lenL;

	int ans = qmod(calc(R, lenR) - calc(L, lenL) + mod);
	printf("%d\n", ans);
}

int main()
{
	int ttt;
	scanf("%d", &ttt);
	while (ttt--)
		solve();
	return 0;
}

T3

没有写 #include <vector>
本地编译过了。
\(25pts \to 0pt\)
这道题,先 \(dfs\)\(a\)\(b\) 的那条路径,然后路径上的每个点下面都会挂着一个子树,我们求出 \(maxd[x]\) = \(x\) 点在子树中最远走的路径长度。
如果小 \(a\) 走着走着走到了一个子树里,那么小 \(a\) 的答案肯定就是 \(maxd[a]\),而小 \(b\) 可以选择 \(next\_point[a]\)\(b\) 的任意一个子树中选择一个子树去走.
我们先看 \(a,b\) 都顶到头的时候,也就是他们只能走一个子树的时候。
这是,我们求出这时的答案 \(now1\)
假设最后一步是 \(a\) 走的。
那么我们让 \(a\) 退回去,那么假设 \(a\) 要在这个地方进子树,就可以统计答案。
\(b\) 也同理。
但是我调了一个晚上没有调出来。。。
代码:

#include <bits/stdc++.h>
#define N 500005
using namespace std;

template <typename T>
inline void read(T &num)
{
	T x = 0, f = 1;
	char ch = getchar();
	for (; ch > '9' || ch < '0'; ch = getchar())
		if (ch == '-')
			f = -1;
	for (; ch <= '9' && ch >= '0'; ch = getchar())
		x = (x << 3) + (x << 1) + (ch ^ '0');
	num = x * f;
}

int n, A, B;
vector<pair<int, int>> E[N];
int chain[N], clen[N], cnt, maxd[N];
int lg2[N], st1[21][N], st2[21][N];

bool dfs(int x, int dest, int fa)
{
	if (x == dest)
	{
		chain[++cnt] = x;
		clen[cnt] = 0;
		return true;
	}
	for (auto [y, w] : E[x])
		if (y != fa)
		{
			if (dfs(y, dest, x))
			{
				chain[++cnt] = x;
				clen[cnt] = w;
				return true;
			}
		}
	return false;
}

int getd(int x, int fa)
{
	int mx = 0;
	for (auto [y, w] : E[x])
		if (y != fa)
		{
			mx = max(mx, w + getd(y, x));
		}
	return mx;
}

inline int qry1(int l, int r)
{
	int k = lg2[r - l + 1];
	return max(st1[k][l], st1[k][r - (1 << k) + 1]);
}

inline int qry2(int l, int r)
{
	int k = lg2[r - l + 1];
	return max(st2[k][l], st2[k][r - (1 << k) + 1]);
}

int main()
{
	read(n);
	read(A);
	read(B);
	for (int i = 1, u, v, w; i < n; i++)
	{
		read(u);
		read(v);
		read(w);
		E[u].push_back({v, w});
		E[v].push_back({u, w});
	}
	dfs(B, A, 0);
	chain[0] = chain[cnt + 1] = 0;
	for (int i = 2; i <= cnt; i++)
		clen[i] += clen[i - 1];
	for (int i = 1; i <= cnt; i++)
	{
		int x = chain[i];
		for (auto [y, w] : E[x])
		{
			if (y != chain[i - 1] && y != chain[i + 1])
				maxd[i] = max(maxd[i], w + getd(y, x));
		}
		st1[0][i] = maxd[i] + clen[i];
		st2[0][i] = maxd[i] - clen[i];
	}
	lg2[1] = 0;
	for (int i = 2; i <= cnt; i++)
		lg2[i] = lg2[i >> 1] + 1;
	for (int l = 1; (1 << l) <= cnt; l++)
	{
		for (int i = 1; i + (1 << l) - 1 <= cnt; i++)
		{
			st1[l][i] = max(st1[l - 1][i], st1[l - 1][i + (1 << (l - 1))]);
			st2[l][i] = max(st2[l - 1][i], st2[l - 1][i + (1 << (l - 1))]);
		}
	}
	int ans = 0;
	if (cnt & 1)
		ans = st2[0][((cnt + 1) >> 1) + 1] + clen[cnt] - st1[0][(cnt + 1) >> 1];
	else
		ans = st1[0][(cnt + 1) >> 1] - (st2[0][((cnt + 1) >> 1) + 1] + clen[cnt]);

	for (int i = cnt - 3; i >= 0; i--)
	{
		int l = 1 + ((i + 1) >> 1), r = cnt - (i >> 1);
		if (i & 1)
			ans = max(st2[0][r] + clen[cnt] - qry1(l, r - 1), -ans);
		else
			ans = max(st1[0][l] - (qry2(l + 1, r) + clen[cnt]), -ans);
	}
	printf("%d\n", ans);
	return 0;
}

T4

猜了个 \(30pts\) 的结论,实则 \(10pts\)
有点懵。贴一个老师的题解:
image

这是代码:

#include <bits/stdc++.h>
#define N 1000005
#define M 105
using namespace std;
typedef long long ll;
typedef __int128 i128;

template <typename T>
void write(T num)
{
	if (num < 0)
		putchar('-'), num = -num;
	if (num >= 10)
		write(num / 10);
	putchar(num % 10 + '0');
}

int pr[N], np[N], ptot;
void init()
{
	int n = 1000000;
	for (int i = 2; i <= n; i++)
	{
		if (!np[i])
			pr[++ptot] = i;
		for (int j = 1; j <= ptot && i * pr[j] <= n; j++)
		{
			np[i * pr[j]] = 1;
			if (i % pr[j] == 0)
				break;
		}
	}
}

ll pfac[M];
int vis[M], match[M], rev[M];

bool dfs(int x, int m)
{
	for (int j = 1; j <= m; j++)
		if (!vis[j] && x % pfac[j] != 0)
		{
			vis[j] = 1;
			if (!match[j] || dfs(match[j], m))
			{
				match[j] = x;
				rev[x] = j;
				return true;
			}
		}
	return false;
}

void solve()
{
	int n, m;
	ll k;
	scanf("%d %lld", &n, &k);
	if (n == 2)
	{
		printf("%lld %lld\n", 2 * k, k);
		return;
	}

	ll tmp = k;
	m = 0;
	for (int i = 1; i <= ptot && 1ll * pr[i] * pr[i] <= tmp; i++)
	{
		if (tmp % pr[i] == 0)
		{
			pfac[++m] = pr[i];
			while (tmp % pr[i] == 0)
				tmp /= pr[i];
		}
	}
	if (tmp)
		pfac[++m] = tmp;

	if (m < n)
	{
		puts("-1");
		return;
	}

	for (int i = 1; i <= n; i++)
		rev[i] = 0;
	for (int j = 1; j <= m; j++)
		match[j] = 0;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
			vis[j] = 0;
		if (!dfs(i, m))
		{
			puts("-1");
			return;
		}
	}

	for (int i = 1; i <= n; i++)
	{
		write((i128)i * k / pfac[rev[i]]);
		putchar(' ');
	}
	putchar('\n');
}

int main()
{
	init();
	int ttt;
	scanf("%d", &ttt);
	while (ttt--)
		solve();
	return 0;
}
posted @ 2025-10-02 20:54  SigmaToT  阅读(3)  评论(0)    收藏  举报