其他分享
首页 > 其他分享> > 「省选测试」拾壹

「省选测试」拾壹

作者:互联网

划分序列

部分分很好打,给得也很足

很显然是二分答案,关键在于去怎么 \(check\)

考虑既有正数又有负数的情况,会发现我们既可以求出权值和 \(\leq x\) 的最小段数,也可以求出权值和 \(\leq x\) 的最大段数,不妨考虑直接 \(dp\)

定义 \(f[n]\) 表示 \(1\sim n\) 可以划分出的最大段数,\(g[n]\) 表示 \(1\sim n\) 可以划分出的最小段数

考虑转移

\[f[i]=\max\{[sum[i]-sum[j - 1] \leq x]f[j]\}+1 \]

\[g[i]=\max\{[sum[i]-sum[j - 1] \leq x]g[j]\}+1 \]

但是这样直接做是 \(\Theta (n^2)\) 的,对于中间的那个条件,可以考虑离散化一下,然后用权值线段树或者是树状数组去优化一下,从而做到单次 \(check\) 是 \(n\log n\) 的

代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 1e5 + 50, INF = 0x3f3f3f3f;

inline int read () {
	register int x = 0, w = 1;
	register char ch = getchar ();
	for (; ch < '0' || ch > '9'; ch = getchar ()) if (ch == '-') w = -1;
	for (; ch >= '0' && ch <= '9'; ch = getchar ()) x = x * 10 + ch - '0';
	return x * w;
}

int n, m, len, L = - INF, R = INF;
int a[maxn], b[maxn], sum[maxn], res[maxn], tmp[maxn];
int f[maxn], g[maxn];

inline void Insert1 (register int x, register int val) {
	for (; x; x -= x & -x) f[x] = max (f[x], val);
}

inline int Query1 (register int x, register int ans = -INF) {
	for (; x <= maxn; x += x & -x) ans = max (ans, f[x]);
	return ans;
}

inline void Insert2 (register int x, register int val) {
	for (; x; x -= x & -x) g[x] = min (g[x], val);
}

inline int Query2 (register int x, register int ans = INF) {
	for (; x <= maxn; x += x & -x) ans = min (ans, g[x]);
	return ans;
}

inline bool Check (register int x, register int ans1 = 0, register int ans2 = 0) {
	b[len = 1] = x, memset (f, - 0x3f, sizeof f), memset (g, 0x3f, sizeof g);
	for (register int i = 1; i <= n; i ++) b[++ len] = sum[i], b[++ len] = x + sum[i];
	sort (b + 1, b + len + 1), len = unique (b + 1, b + len + 1) - b - 1;
	for (register int i = 1; i <= n; i ++) res[i] = lower_bound (b + 1, b + len + 1, sum[i]) - b, tmp[i] = lower_bound (b + 1, b + len + 1, x + sum[i]) - b;
	x = lower_bound (b + 1, b + len + 1, x) - b, Insert1 (x, 0), Insert2 (x, 0);
	for (register int i = 1; i <= n; i ++) ans1 = Query1 (res[i]) + 1, Insert1 (tmp[i], ans1);
	for (register int i = 1; i <= n; i ++) ans2 = Query2 (res[i]) + 1, Insert2 (tmp[i], ans2);
	return ans2 <= m && m <= ans1;
}

int main () {
	n = read(), m = read();
	for (register int i = 1; i <= n; i ++) a[i] = read(), sum[i] = sum[i - 1] + a[i];
	while (L <= R) {
		register int mid = (L + R) >> 1;
		if (Check (mid)) R = mid - 1;
		else L = mid + 1;
	}
	printf ("%d\n", L);
	return 0;
}

Ring

对于每个左端点 \(l\) 我们可以求出来最小的符合条件的 \(r\),这样可以做到用双指针 \(\Theta (n)\) 去扫

在判断是否符合条件的时候用 \(LCT\) 去维护一下就好啦

代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 3e5 + 50, INF = 0x3f3f3f3f;

inline int read () {
	register int x = 0, w = 1;
	register char ch = getchar ();
	for (; ch < '0' || ch > '9'; ch = getchar ()) if (ch == '-') w = -1;
	for (; ch >= '0' && ch <= '9'; ch = getchar ()) x = x * 10 + ch - '0';
	return x * w;
}

int n, m, q, R[maxn];

struct Edge {
	int from, to;
} e[maxn];

struct Tree {
	int fa, ch[2], lazy;
} tree[maxn];

inline bool Isroot (register int rt) {
	return tree[tree[rt].fa].ch[0] != rt && tree[tree[rt].fa].ch[1] != rt;
}

inline void Pushdown (register int rt) {
	if (! tree[rt].lazy) return;
	tree[tree[rt].ch[0]].lazy ^= 1, tree[tree[rt].ch[1]].lazy ^= 1;
	tree[rt].lazy = 0, swap (tree[rt].ch[0], tree[rt].ch[1]);
}

inline void Recall (register int rt) {
	if (! Isroot (rt)) Recall (tree[rt].fa);
	Pushdown (rt);
}

inline void Rotate (register int x) {
	register int y = tree[x].fa, z = tree[y].fa, k = tree[y].ch[1] == x;
	if (! Isroot (y)) tree[z].ch[tree[z].ch[1] == y] = x; tree[x].fa = z;
	tree[y].ch[k] = tree[x].ch[! k], tree[tree[x].ch[! k]].fa = y;
	tree[x].ch[! k] = y, tree[y].fa = x;
}

inline void Splay (register int x) {
	Recall (x);
	while (! Isroot (x)) {
		register int y = tree[x].fa, z = tree[y].fa;
		if (! Isroot (y)) (tree[y].ch[0] == x) == (tree[z].ch[0] == y) ? Rotate (y) : Rotate (x);
		Rotate (x);
	}
}

inline void Access (register int x, register int y = 0) {
	for (; x; y = x, x = tree[x].fa) Splay (x), tree[x].ch[1] = y;
}

inline void Makeroot (register int x) {
	Access (x), Splay (x), tree[x].lazy ^= 1;
}

inline int Findroot (register int x) {
	Access (x), Splay (x);
	while (tree[x].ch[0]) x = tree[x].ch[0];
	return x;
}

inline void Split (register int x, register int y) {
	Makeroot (x), Access (y), Splay (y);
}

inline void Link (register int x, register int y) {
	Makeroot (x);
	if (Findroot (y) != x) tree[x].fa = y;
}

inline void Cut (register int x, register int y) {
	if (Findroot (x) != Findroot (y)) return;
	Split (x, y);
	if (tree[y].ch[0] == x && tree[x].ch[1] == 0) tree[y].ch[0] = tree[x].fa = 0;
}

int main () {
	n = read(), m = read(), q = read();
	for (register int i = 1; i <= m; i ++) e[i].from = read(), e[i].to = read();
	register int r = 1;
	for (register int l = 1; l <= m; l ++) {
		while (r <= m) {
			register int u = e[r].from, v = e[r].to;
			if (Findroot (u) == Findroot (v)) break;
			else Link (u, v), r ++;
		}
		R[l] = r, Cut (e[l].from, e[l].to);
	}
	while (q --) {
		register int l = read(), r = read();
		if (r >= R[l]) puts (">_<");
		else puts ("QAQ");
	}
	return 0;
}

Match

对于最后答案,打表(能打出来???)或者推式子(我还不会),得到这样一个通项公式

\[ans=\frac{10n^2-13n^1-1n^0+4n^{-1}}{45} \]

然后可以带进去直接做

代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int maxn = 1e5 + 50, INF = 0x3f3f3f3f, mod = 1e9 + 7;

inline int read () {
	register int x = 0, w = 1;
	register char ch = getchar ();
	for (; ch < '0' || ch > '9'; ch = getchar ()) if (ch == '-') w = -1;
	for (; ch >= '0' && ch <= '9'; ch = getchar ()) x = x * 10 + ch - '0';
	return x * w;
}

inline int qpow (register int a, register int b, register int ans = 1) {
	for (; b; b >>= 1, a = 1ll * a * a % mod) if (b & 1) ans = 1ll * ans * a % mod;
	return ans;
}

int n;

int main () {
	n = read();
	printf ("%lld\n", 1ll * ((10ll * n * n % mod - 13ll * n % mod - 1 + 4ll * qpow (n, mod - 2) % mod) % mod + mod) % mod * qpow (45, mod - 2) % mod);
	return 0;
}

标签:拾壹,ch,leq,省选,段数,int,测试,include,mod
来源: https://www.cnblogs.com/Rubyonly233/p/14341593.html