Loading

NOIP 二十四

A.

容易想到将不同的质因数分开考虑,对于一个 \(p^k\) 的质因子和一个集合 \(S\) ,可以选择任意一种次幂与 \(S\) 中的元素相乘或者单独成为一个元素,也可以不加入集合。

\(f'_{\left|S\right|}=f_{\left|S\right|} \times(1+k\times \left|S\right|) + k\times f_{\left|S\right|-1}\)

复杂度 \(\mathcal O(V+q(\log V+\omega^2(V)))\)\(\omega(n)\) 表示 \(n\) 本质不同的质因子个数,\(\omega(10^8)<9\)

点击查看

#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = (a), ed##i = (b); i <= ed##i; ++i)
#define rep(i, a, b) for (int i = (a), ed##i = (b); i >= ed##i; --i)
#define il inline
#define arr(ty, tn) std::array<ty, tn>
#define gmx(a, b) a = std::max(a, b)
#define gmn(a, b) a = std::min(a, b)

template <typename T>
void _debug(const T& t) { std::cerr << t << '\n'; }
template <typename T, typename... Args>
void _debug(const T& t, const Args&...res) { std::cerr << t << ' '; _debug(res...); }
#define debug(...) _debug(#__VA_ARGS__ " =", __VA_ARGS__)

const int LN = 1e8 + 7;
const int mod = 998244353;
typedef long long ll;
typedef std::pair<int, int> PII;

bool FIRPOS;

int f[100];
int o[LN], p[LN / 17]; std::bitset <LN> np;

bool ENDPOS;

il int add(int u, int v) { return u + v >= mod ? u + v - mod : u + v; }
il void upa(int&u,int v) { u = add(u, v); }
il int mul(ll u, ll v) { return u * v >= mod ? u * v % mod : u * v; }
il void upm(int&u,int v) { u = mul(u, v); }
il int MyPow(int a, int b) { int ans = 1; for (;b; b >>= 1, upm(a, a)) if (b & 1) upm(ans, a); return ans; }

int main() {
	std::ios::sync_with_stdio(false),
	std::cin.tie(nullptr), std::cout.tie(nullptr);
	int c1 = clock(), Test, n, cnt = 0;

	lep(i, 2, LN - 1) {
		if (!np[i]) p[cnt++] = i, o[i] = i;
		lep(j, 0, cnt - 1) if (i * p[j] < LN) {
			np.set(i * p[j]), o[i * p[j]] = p[j];
			if (i % p[j] == 0) break;
		} else break;
	}

	std::cin >> Test;
	
	int k, t, V, ans;
	while (Test--) {
		std::cin >> n;
		std::memset(f, 0, sizeof(f)), f[V = 0] = 1;
		while (n > 1) {
			t = o[n], k = 0, ++V;
			while (n % t == 0) ++k, n /= t;
			rep(i, V, 1) upa(f[i], mul(k, add(mul(i, f[i]), f[i - 1])));
		}
		ans = 0; lep(i, 1, V) upa(ans, f[i]);
		std::cout << ans << '\n';
	}

	std::cerr << clock() - c1 << " ms " << fabs(&ENDPOS - &FIRPOS) / 1024 / 1024 << " MB\n";
	return 0;
}

B.

喵喵题。

容易写出 \(\mathcal O(n^2)\) 的暴力。

发现如果已经到达过 \((a, b)\), \((b, c)\) ,则 \((a, c)\) 状态就是没有必要记录的。

如果 \((a, c)\) 最终不可区分,则无用,如果可区分,则 \(b\) 一定可以通过同样的路径区分且长度更短,因为这个状态更早。

于是使用并查集维护这个过程即可做到 \(\mathcal O(n)\)

点击查看

#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = (a), ed##i = (b); i <= ed##i; ++i)
#define rep(i, a, b) for (int i = (a), ed##i = (b); i >= ed##i; --i)
#define il inline
#define arr(ty, tn) std::array<ty, tn>
#define gmx(a, b) a = std::max(a, b)
#define gmn(a, b) a = std::min(a, b)

template <typename T>
void _debug(const T& t) { std::cerr << t << '\n'; }
template <typename T, typename... Args>
void _debug(const T& t, const Args&...res) { std::cerr << t << ' '; _debug(res...); }
#define debug(...) _debug(#__VA_ARGS__ " =", __VA_ARGS__)

const int LN = 2e6 + 7;
const int inf = 1e8;
typedef long long ll;
typedef std::pair<int, int> PII;

bool FIRPOS;

int n, a, b, f[LN], g[LN], c[LN], fa[LN];

bool ENDPOS;

int fnd(int x) { return fa[x] == x ? x : fa[x] = fnd(fa[x]); }
void mrg(int x, int y) { if ((x = fnd(x)) != (y = fnd(y))) fa[x] = y; }
int getdis(int a, int b) {
	std::queue <arr(int, 3)> q; int u, v, d;
	q.push({a, b, 0});
	while (!q.empty()) {
		auto t = q.front(); q.pop(); u = t[0], v = t[1], d = t[2];
		if (c[u] != c[v]) return d;
		if (fnd(f[u]) != fnd(f[v])) mrg(f[u], f[v]), q.push({f[u], f[v], d + 1});
		if (fnd(g[u]) != fnd(g[v])) mrg(g[u], g[v]), q.push({g[u], g[v], d + 1});
	}
	return inf;
}

int main() {
	std::ios::sync_with_stdio(false),
	std::cin.tie(nullptr), std::cout.tie(nullptr);
	int c1 = clock(), Test;
	
	std::cin >> Test;
	while (Test--) {
		std::cin >> n;
		lep(i, 1, n) std::cin >> f[i], fa[i] = i; lep(i, 1, n) std::cin >> g[i]; lep(i, 1, n) std::cin >> c[i];
		std::cin >> a >> b;
		int da = getdis(a, b);
		if (da == inf) std::cout << "Impossible\n";
		else std::cout << da << '\n';
	}

	std::cerr << clock() - c1 << " ms " << fabs(&ENDPOS - &FIRPOS) / 1024 / 1024 << " MB\n";
	return 0;
}

C.

首先考虑只有正数,我们将存在一个数与其相乘 \(>C\) 的称为大数,否则称为小数,排序后小数一定是一段前缀。

刻画排列考虑连续段 DP,我们想要将限制从严格向宽松枚举,从大到小加入小数。

在所有与其冲突的数被加入后加入大数。

这样大数被加入时只能独立成为一个连续段,等待后面合法的小数将其分割成合法状态。

而小数则可以有

  • 独立成为新的连续段。
  • 合并两个连续段。
  • 延续一个连续段。

三种转移。

最后输出只有一个连续段的结果。

如果再加上负数呢?因为正数和负数相邻一定合法,所以我们将正负数分别做如上事情,最后交替合并即可。

具体的,如果有 \(i\) 个正数的连续段,则负数连续段个数可以为 \(i-1,i,i+2\) ,注意 \(i\)\(\times 2\) 的系数。

点击查看

#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = (a), ed##i = (b); i <= ed##i; ++i)
#define rep(i, a, b) for (int i = (a), ed##i = (b); i >= ed##i; --i)
#define il inline
#define arr(ty, tn) std::array<ty, tn>
#define gmx(a, b) a = std::max(a, b)
#define gmn(a, b) a = std::min(a, b)

template <typename T>
void _debug(const T& t) { std::cerr << t << '\n'; }
template <typename T, typename... Args>
void _debug(const T& t, const Args&...res) { std::cerr << t << ' '; _debug(res...); }
#define debug(...) _debug(#__VA_ARGS__ " =", __VA_ARGS__)

const int LN = 6000 + 7;
const int mod = 1e9 + 7;
typedef long long ll;
typedef std::pair<int, int> PII;

bool FIRPOS;

int n, C, a[LN], f[2][LN], g[LN];
int b[LN], c[LN]; std::vector <int> o[LN];

bool ENDPOS;

il int add(int u, int v) { return u + v >= mod ? u + v - mod : u + v; }
il void upa(int&u,int v) { u = add(u, v); }
il int mul(ll u, ll v) { return u * v >= mod ? u * v % mod : u * v; }
il void upm(int&u,int v) { u = mul(u, v); }
il int MyPow(int a, int b) { int ans = 1; for (; b; b >>= 1, upm(a, a)) if (b & 1) upm(ans, a); return ans; }
int sol(int a[]) {
	int op = 0, m = a[0], p = 0; 
	std::memset(f[op], 0, sizeof(f[op])), f[op][0] = 1;
	std::sort(a + 1, a + 1 + m);
	
	int l, r, md;
	lep(i, 0, m) o[i].clear();
	lep(i, 1, m) { l = 0, r = i - 1;
		while (l < r) { md = (l + r + 1) >> 1;
			if (1ll * a[md] * a[i] <= C) l = md;
			else r = md - 1;
		}
		if (l != i - 1) o[l].push_back(a[i]);
		else p = i;
	}
	
	rep(i, p, 0) {
		for (auto t : o[i]) {
			op ^= 1, std::memset(f[op], 0, sizeof(f[op]));
			lep(i, 1, n) upa(f[op][i], mul(f[op ^ 1][i - 1], i));
		}
		if (!i) break;
		op ^= 1, std::memset(f[op], 0, sizeof(f[op]));
		lep(i, 1, n) upa(f[op][i], mul(f[op ^ 1][i - 1], i)), 
			upa(f[op][i], mul(f[op ^ 1][i], i + i)), upa(f[op][i], mul(f[op ^ 1][i + 1], i));
	}
	return op;
}

int main() {
	std::ios::sync_with_stdio(false),
	std::cin.tie(nullptr), std::cout.tie(nullptr);
	int c1 = clock();

	std::cin >> n >> C;
	lep(i, 1, n) {
		std::cin >> a[i];
		if (a[i] > 0) b[++*b] = a[i]; else c[++*c] = -a[i];
	}
	int po = sol(b);
	lep(i, 0, n) g[i] = f[po][i];
	int op = sol(c);
	
	int ans = 0;
	lep(i, 1, n) upa(ans, mul(g[i], add(add(f[op][i], f[op][i]), add(f[op][i + 1], f[op][i - 1]))));
	std::cout << ans << '\n';
	
	std::cerr << clock() - c1 << " ms " << fabs(&ENDPOS - &FIRPOS) / 1024 / 1024 << " MB\n";
	return 0;
}

D.

使用线段树维护区间内出现元素的桶,即 bitset ,然后查询可见 小清新人渣的本愿

为了避免 \(2\) 倍的常数,手写 bitset代码最大难点),只维护正的,然后可以 \(\frac{n}{\omega}\log \omega\) 翻转得到反的。

因为线段树空间还开不下,于是使用底层分块线段树优化,即节点长度 \(\le B\) 作为叶子节点暴力处理。

则复杂度 \(\frac{n}{w}\log \frac{n}{B} + B\) ,取 \(B=\frac{n}{\omega}\) ,得到复杂度 \(\mathcal O(\frac{n^2\log\omega}{\omega})\) 。(\(\frac{n^2}{3}\))

\(7\) s 可过。

点击查看

#include <bits/stdc++.h>
#define lep(i, a, b) for (int i = (a), ed##i = (b); i <= ed##i; ++i)
#define rep(i, a, b) for (int i = (a), ed##i = (b); i >= ed##i; --i)
#define il inline

const int LN = 2e5 + 7;
const int B = 6;
const int M = LN / 60;
typedef unsigned long long ull;
typedef std::pair<int, int> PII;

bool FIRPOS;

int up, a[LN];
ull b[1 << B][M], res[M], tmp[M];
int dl[1 << B], co[1 << B]; std::bitset <LN> op;
ull r1[M];
int n, m, V, id;

bool ENDPOS;

il void s1(ull b[], int v) { b[v >> 6] |= (1ull << (v & 63)); }
il void cls(ull b[], int v) { b[v >> 6] = 0; }
il void cls(ull b[]) { lep(i, 0, up - 1) b[i] = 0; }
il bool ck(ull b[], int v) { return (b[v >> 6] >> (v & 63)) & 1; }
il ull rev(ull b) {
    b = ((b >> 1) & 0x5555555555555555ULL) | ((b & 0x5555555555555555ULL) << 1);
    b = ((b >> 2) & 0x3333333333333333ULL) | ((b & 0x3333333333333333ULL) << 2);
    b = ((b >> 4) & 0x0F0F0F0F0F0F0F0FULL) | ((b & 0x0F0F0F0F0F0F0F0FULL) << 4);
    b = ((b >> 8) & 0x00FF00FF00FF00FFULL) | ((b & 0x00FF00FF00FF00FFULL) << 8);
    b = ((b >> 16) & 0x0000FFFF0000FFFFULL) | ((b & 0x0000FFFF0000FFFFULL) << 16);
    b = (b >> 32) | (b << 32);
    return b;
}
il void shift(ull b[], int v, int op) {
	int dl = (v >> 6), ld = (v & 63), rd = 64 - ld;
	if (!ld) {
		if (!op) {
			lep(i, 0, up - dl - 1) r1[i + dl] = b[i];
			lep(i, 0, dl - 1) r1[i] = 0;
		}
		else {
			lep(i, 0, up - dl - 1) r1[i + dl] = b[i];
			lep(i, up - dl, up - 1) r1[i + dl - up] = b[i];
		}
	} else {
		if (!op) {
			lep(i, 0, up - dl - 1) r1[i + dl] = (b[i] << ld) | (i ? (b[i - 1] >> rd) : 0ull);
			lep(i, 0, dl - 1) r1[i] = 0;
		}
		else {
			lep(i, 0, up - dl - 1) r1[i + dl] = (b[i] << ld) | ((i ? b[i - 1] : b[up - 1]) >> rd);
			lep(i, up - dl, up - 1) r1[i + dl - up] = (b[i] << ld) | (b[i - 1] >> rd);
		}
	}
	lep(i, 0, up - 1) b[i] = r1[i];
}
#define ls p << 1
#define rs p << 1 | 1
#define md ((s + t) >> 1)
il void pu(int p) { lep(i, 0, up - 1) b[p][i] = b[ls][i] | b[rs][i]; }
il void upd(int p, int s, int t, int k, int c) {
	if (~c) {
		cls(b[p]), s1(b[p], c);
		if (op[p]) lep(i, s, t) a[i] = c;
		else co[p] = c, dl[p] = 0;
	} else if (k) {
		shift(b[p], k, 1);
		if (op[p]) lep(i, s, t) a[i] = (a[i] + k) % V;
		else if (~co[p]) co[p] = (co[p] + k) % V;
		else dl[p] = (dl[p] + k) % V;
	}
}
il void pd(int p, int s, int t) {
	if (~co[p]) upd(ls, s, md, 0, co[p]), upd(rs, md + 1, t, 0, co[p]), co[p] = -1;
	if (dl[p]) upd(ls, s, md, dl[p], -1), upd(rs, md + 1, t, dl[p], -1), dl[p] = 0;
}
void bd(int dep = 1, int s = 1, int t = n, int p = 1) {
	co[p] = -1, dl[p] = 0; cls(b[p]); lep(i, s, t) s1(b[p], a[i]);
	if (s == t or dep == B) return op.set(p), void();
	bd(dep + 1, s, md, ls), bd(dep + 1, md + 1, t, rs);
}
void delta(int l, int r, int x, int dep = 1, int s = 1, int t = n, int p = 1) {
	if (r < s or t < l) return; if (l <= s and t <= r) return upd(p, s, t, x, -1);
	if (dep == B) {
		lep(i, std::max(l, s), std::min(r, t)) a[i] = (a[i] + x) % V;
		cls(b[p]); lep(i, s, t) s1(b[p], a[i]);
		return;
	} pd(p, s, t);
	delta(l, r, x, dep + 1, s, md, ls), delta(l, r, x, dep + 1, md + 1, t, rs); pu(p);
}
void color(int l, int r, int x, int dep = 1, int s = 1, int t = n, int p = 1) {
	if (r < s or t < l) return; if (l <= s and t <= r) return upd(p, s, t, 0, x);
	if (dep == B) {
		lep(i, std::max(l, s), std::min(r, t)) a[i] = x;
		cls(b[p]); lep(i, s, t) s1(b[p], a[i]);
		return;
	} pd(p, s, t);
	color(l, r, x, dep + 1, s, md, ls), color(l, r, x, dep + 1, md + 1, t, rs); pu(p);
}
void qry(int l, int r, int dep = 1, int s = 1, int t = n, int p = 1) {
	if (r < s or t < l) return; if (l <= s and t <= r) { lep(i, 0, up - 1) res[i] |= b[p][i]; return; }
	if (dep == B) { lep(i, std::max(l, s), std::min(r, t)) s1(res, a[i]); return; } pd(p, s, t);
	qry(l, r, dep + 1, s, md, ls), qry(l, r, dep + 1, md + 1, t, rs);
}
#undef ls
#undef rs
#undef md

int main() {
	std::ios::sync_with_stdio(false),
	std::cin.tie(nullptr), std::cout.tie(nullptr);
	int c1 = clock();
	
	std::cin >> n >> m >> V >> id, up = V >> 6;
	lep(i, 1, n) std::cin >> a[i];
	bd();

	int op, l, r, x, g = 0;
	while (m--) {
		std::cin >> op >> l >> r >> x, l ^= g, r ^= g; if (l > r) std::swap(l, r);
		if (op == 1) color(l, r, x);
		else if (op == 2) delta(l, r, x);
		else {
			cls(res), qry(l, r); bool ans = false;
			if (op == 3) {
				lep(i, 0, up - 1) tmp[i] = res[i]; shift(tmp, x, 0);
				lep(i, 0, up - 1) if (tmp[i] & res[i]) { ans = true; break; }
			}
			else if (op == 4) {
				lep(i, 0, up - 1) tmp[i] = rev(res[up - 1 - i]);
				shift(res, V - 1 - x, 0); lep(i, 0, up - 1) if (tmp[i] & res[i]) { ans = true; break; }
			} else if (x) {
				lep(i, 1, V - 1) {
					if (x % i == 0 and ck(res, i) and ck(res, x / i)) { ans = true; break; }
					if (x / i <= i) break;
				}
			} else if (ck(res, 0)) ans = true;
			if (ans) g = l, std::cout << "Yes\n";
			else std::cout << "No\n";
		}
	}

	std::cerr << clock() - c1 << " ms " << fabs(&ENDPOS - &FIRPOS) / 1024 / 1024 << " MB\n";
	return 0;
}

posted @ 2025-10-15 22:50  qkhm  阅读(11)  评论(0)    收藏  举报