「赛后总结」高考集训:NOIP 模拟测试 A3

「赛后总结」高考集训:NOIP 模拟测试 A3

点击查看目录


今日推歌

image


T1 谜之阶乘

思路

签到题。

根据数学直觉,\(a, b\) 相差不大。

根据数学直觉,\(n^{\tfrac{1}{b - a}}\)\(\dfrac{a + b}{2}\)相差不大(\(\leftarrow\) 计算器带给我的)。

于是暴力枚举 \(b - a\),找到 \(a\) 然后 check 一下。

代码

点击查看代码
const ll N = 110;
namespace SOLVE {
	ll n, cnt;
	std::pair <ll, ll> ans[N];
	inline ll rnt () {
		ll x = 0, w = 1; char c = getchar ();
		while (!isdigit (c)) { if (c == '-') w = -1; c = getchar (); }
		while (isdigit (c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar ();
		return x * w;
	}
	inline void In () {
		n = rnt (), cnt = 0;
		return;
	}
	inline void Solve () {
		if (n != 1) cnt = 1, ans[1].first = n, ans[1].second = n - 1;
		_for (i, 2, 64) {
			ll tmp = std::floor (pow (n, 1.0 / i)), s = 1, f = 0;
			tmp = tmp - i / 2;
			while (s < n){
				++tmp, s = 1;
				if (tmp <= 0) continue;
				_for (j, 0, i - 1) {
					s *= (tmp + j);
					if (s > n || s < 0ll) break;
				}
				if (s == n) break;
			}
			if (tmp <= 1) break;
			if (s == n) ++cnt, ans[cnt].first = tmp + i - 1, ans[cnt].second = tmp - 1;
		}
		return;
	}
	inline void Out () {
		std::sort (ans + 1, ans + cnt + 1);
		printf ("%lld\n", cnt ? cnt : -1);
		_for (i, 1, cnt) printf ("%lld %lld\n", ans[i].first, ans[i].second);
		return;
	}
}

T2 子集

思路

好厉害的构造!

首先特判掉不合法情况:

  • \(n = k.\)
  • \(n = 1.\)
  • \(k\nmid \frac{n(n+1)}2.\)

然后如果 \(\frac{n}{k}\) 为偶数就蛇形填。

否则你先把前三列填出来,然后再蛇形填。

有点。难描述。建议。直接看码。

这个常数不太好不放了,push_back ()clear () 太多的缘故?

代码

点击查看代码
const ll N = 1e6 + 10;
namespace SOLVE {
	ll n, k, yn; std::vector <ll> ans[N];
	inline ll rnt () {
		ll x = 0, w = 1; char c = getchar ();
		while (!isdigit (c)) { if (c == '-') w = -1; c = getchar (); }
		while (isdigit (c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar ();
		return x * w;
	}
	inline void In () {
		n = rnt (), k = rnt ();
		return;
	}
	inline void Solve () {
		_for (i, 1, k) ans[i].clear ();
		if (k == 1) {
			_for (i, 1, n) ans[1].push_back (i);
			return;
		}
		if (n == 1 || n == k) { yn = 1; return; }
		if ((n * (n + 1) / 2) % k) { yn = 1; return; }
		if ((n / k) & 1) {
			ll t = 0, qwq = (1 + 3 * k) * 3 / 2;
			_for (i, 1, k) ans[i].push_back (++t);
			_for (i, (k + 1) / 2 + 1, k) ans[i].push_back (++t);
			_for (i, 1, (k + 1) / 2) ans[i].push_back (++t);
			_for (i, 1, k) ans[i].push_back (qwq - ans[i][0] - ans[i][1]);
			t = 3 * k;
			_for (i, 4, n / k) {
				if (i & 1) _for (j, 1, k) ans[j].push_back (++t);
				else for_ (j, k, 1) ans[j].push_back (++t);
			}
		}
		else {
			ll t = 0;
			_for (i, 1, n / k) {
				if (i & 1) _for (j, 1, k) ans[j].push_back (++t);
				else for_ (j, k, 1) ans[j].push_back (++t);
			}
		}
		return;
	}
	inline void Out () {
		if (yn) puts ("No"), yn = 0;
		else {
			puts ("Yes");
			_for (i, 1, k) {
				far (j, ans[i]) printf ("%lld ", j);
				puts ("");
			}
		}
		return;
	}
}

T3 混凝土粉末

思路

赛时用的主席树,复杂度是 \(O(q\log_2q\log_2n)\)的。因为差分所以常数优于他人,多拿了 5pts。

update:差分的人严格多于不差分的,那你们就是纯粹常数没我好 [骄傲]。

考虑离线并差分,用一个树状数组维护在前 \(i\) 次操作后,当前扫到的数的大小。

具体的,从 \(1\) 扫到 \(n\),遇到一个 \(1\) 操作的左端点就把操作的值加上,遇到一个 \(1\) 操作的右端点就把操作的值减去,然后遇到一个 \(2\) 操作就二分查找哪次操作后符合要求。

代码

点击查看代码
const int N = 2e6 + 10;

namespace TREEARRAY {
	class TreeArray {
	private:
		ll b[N];
		inline int lowbit (int x) { return x & (-x); }
	public:
		int q;
		inline void Update (int x, ll y) {
			while (x <= q) b[x] += y, x += lowbit (x);
			return;
		}
		inline ll Query (int x) {
			ll sum = 0;
			while (x > 0) sum += b[x], x -= lowbit (x);
			return sum;
		}
	};
}

namespace SOLVE {
	int n, q, vis[N], ans[N], cm, cq;
	TREEARRAY::TreeArray tr;
	class TMP {
	public:
		int x; ll y; int id;
		inline bool operator < (TMP another) const {
			return x < another.x;
		}
	} mo[N], qu[N];
	inline ll rnt () {
		ll x = 0, w = 1; char c = getchar ();
		while (!isdigit (c)) { if (c == '-') w = -1; c = getchar (); }
		while (isdigit (c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar ();
		return x * w;
	}
	inline void In () {
		n = rnt (), tr.q = q = rnt ();
		_for (i, 1, q) {
			ll op = rnt ();
			if (op == 1) {
				int l = rnt (), r = rnt (); ll h = rnt ();
				mo[++cm] = (TMP){l, h, i}, mo[++cm] = (TMP){r + 1, -h, i};
			}
			else {
				int x = rnt (); ll y = rnt ();
				qu[++cq] = (TMP){x, y, i};
				vis[i] = 1;
			}
		}
		return;
	}
	inline void Solve () {
		std::sort (mo + 1, mo + cm + 1);
		std::sort (qu + 1, qu + cq + 1);
		int p1 = 0, p2 = 0;
		_for (i, 1, n) {
			while (mo[p1 + 1].x == i) ++p1, tr.Update (mo[p1].id, mo[p1].y);
			while (qu[p2 + 1].x == i) {
				++p2;
				if (tr.Query (qu[p2].id) < qu[p2].y) {
					ans[qu[p2].id] = 0;
					continue;
				}
				int l = 1, r = ans[qu[p2].id] = qu[p2].id;
				while (l <= r) {
					bdmd;
					if (tr.Query (mid) < qu[p2].y) l = mid + 1;
					else ans[qu[p2].id] = mid, r = mid - 1;
				}
			}
		}
		return;
	}
	inline void Out () {
		_for (i, 1, q) if (vis[i]) printf ("%d\n", ans[i]);
		return;
	}
}

T4 排水系统

思路

\(f_{u}\) 表示一条边不堵时 \(u\) 点的流量,\(d_{u}\) 表示 \(u\) 点出度,\(g_{u}\) 表示 \(u\) 点的期望流量。

考虑堵一个 \((u, v)\) 造成的影响。

\(v\) 流量会少 \(\dfrac{f_{u}}{d_{u}}\)\(u\) 指向的其他点流量会多 \(\dfrac{f_{u}}{d_{u}(d_{u} - 1)}\)

直接改很慢啊!于是我们把 \(u\) 指向的其他点流量合起来加到 \(u\) 上,给 \(v\) 多减点。

具体一点,\(v\) 流量会少 \(\dfrac{f_{u}}{d_{u}(d_{u} - 1)} + \dfrac{f_{u}}{d_{u}}\)\(u\) 流量会多 \(\dfrac{f_{u}}{d_{u} - 1}\)

代码

点击查看代码
const ll N = 5e5 + 10, P = 998244353;
namespace SOLVE {
	ll n, m, r, k, sum, in[N], vis[N], f[N], g[N];
	class Edge { public: ll v, w; };
	std::vector <Edge> tu[N];
	inline ll rnt () {
		ll x = 0, w = 1; char c = getchar ();
		while (!isdigit (c)) { if (c == '-') w = -1; c = getchar (); }
		while (isdigit (c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar ();
		return x * w;
	}
	inline ll FastPow (ll a, ll b) {
		ll ans = 1;
		while (b) {
			if (b & 1) ans = ans * a % P;
			a = a * a % P, b >>= 1;
		}
		return ans;
	}
	inline void TopoSort () {
		std::queue <ll> q;
		_for (i, 1, n) {
			f[i] = g[i] = 0, vis[i] = in[i];
			if (!in[i]) q.push (i), f[i] = g[i] = 1;
		}
		while (!q.empty ()) {
			ll u = q.front (), cs = tu[u].size (), csa = cs - 1; q.pop ();
			cs = FastPow (cs, P - 2), csa = FastPow (csa, P - 2);
			far (qwq, tu[u]) {
				ll p = qwq.w * sum % P;
				g[u]	 = (g[u]	 + f[u] * csa % P * p % P) % P;
				g[qwq.v] = (g[qwq.v] - f[u] * cs % P * (csa + 1) % P * p % P + P) % P;
				if (!(--vis[qwq.v])) q.push (qwq.v);
			}
			far (qwq, tu[u]) {
				g[qwq.v] = (g[qwq.v] + g[u] * cs % P) % P;
				f[qwq.v] = (f[qwq.v] + f[u] * cs % P) % P;
			}
		}
		return;
	}
	inline void In () {
		n = rnt (), m = rnt (), r = rnt (), k = rnt ();
		_for (i, 1, k) {
			ll u = rnt (), v = rnt (), w = rnt ();
			tu[u].push_back ((Edge){v, w});
			sum = (sum + w) % P, ++in[v];
		}
		return;
	}
	inline void Solve () {
		sum = FastPow (sum, P - 2);
		TopoSort ();
		return;
	}
	inline void Out () {
		_for (i, 1, n) if (tu[i].empty ()) printf ("%lld ", g[i]);
		puts ("");
		return;
	}
}
posted @ 2023-06-13 22:06  K8He  阅读(141)  评论(4编辑  收藏  举报