NOIP A层联测 27

天平

设已选的砝码的集合为$ S $,它的元素的 $ gcd $ 为 $ g $ , 那么它所能拼出来的数都是 \(g\) 的倍数。
因此要想使所有数都被表示出来就要使 \(S\)内的元素的 \(gcd\)等于所有数的 \(gcd\)
因为 \(a_i <= 1e7\)\(1e7\)以内的质因子只有 \(8\) 个,因此答案最多为 \(8\),直接暴搜就彳亍
然而我的常数比较大,暴搜只有 \(98\),于是加了个优化,把前缀 \(gcd\)求出来,然后倒着搜,如果从一个位置往前的数都选上的 \(gcd\)还是比目标大就直接 \(return\)

AC代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

#define Miuna printf ("dai  suki...")
#define mizuki signed 
#define love (1209 & 322 & 901)

namespace LRH 
{
	template <typename Shiodome_miuna> inline void in (Shiodome_miuna &x)
	{
		x = 0;
		char f = 0; char ch;
		while (!isdigit (ch = getchar ())) if (ch == '-') f = 1;
		do
		{
			x = (x << 1) + (x << 3) + (ch ^ 48);
		} while (isdigit (ch = getchar ()));
		if (f) x = -x;
	}
	int stk[20], tp;
	template <typename Shiodome_miuna> inline void ot (Shiodome_miuna x, int f = 2)
	{
		if (x < 0) putchar ('-'), x = -x;
		do
		{
			stk[++ tp] = x % 10;
			x /= 10;
		} while (x);
		while (tp)
		{
			putchar (stk[tp --] | 48);
		}
		if (f == 1) putchar ('\n');
		if (!f) putchar (' ');
	}
}using namespace LRH;
int min (int x, int y) {return x < y ? x : y;}
typedef long long ll;
const int maxn = 50 + 10;
int n, g[maxn], ans = 8, sum;
int a[maxn];
inline int gcd (int x, int y)
{
	while (y)
	{
		int t = x; x = y;
		y = t % x;
	}
	return x;
}
void dfs (int x, int gg)
{
	if (x == 0) return;
	if (sum >= ans) return;
	if (gg == g[n])
	{
		ans = min (ans, sum);
		return;
	}
	if (gcd (gg, g[x - 1]) > g[n]) return;
	sum ++;
	dfs (x - 1, gcd (gg, a[x - 1]));
	sum --;
	dfs (x - 1, gg);
}
mizuki main ()
{
	freopen ("weights.in", "r", stdin);
	freopen ("weights.out", "w", stdout);
	in (n);
	in (a[1]);
	g[1] = a[1];
	for (int i = 2; i <= n; ++ i) in (a[i]), g[i] = gcd (g[i - 1], a[i]);
	for (int i = n; i >= 1; -- i) sum = 1, dfs (i, a[i]);
	ot (ans);
	return love;
}

支配数据

\(1\) ~ \(n\)内每个区间的最小值处理出来存进\(ST\)表里
然后对整个序列开一棵动态开点的线段树就可以了

AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<random>
using namespace std;

#define Miuna printf ("dai  suki...")
#define mizuki signed 
#define love (1209 & 322 & 901)

namespace LRH 
{
	template <typename Shiodome_miuna> inline void in (Shiodome_miuna &x)
	{
		x = 0;
		char f = 0; char ch;
		while (!isdigit (ch = getchar ())) if (ch == '-') f = 1;
		do
		{
			x = (x << 1) + (x << 3) + (ch ^ 48);
		} while (isdigit (ch = getchar ()));
		if (f) x = -x;
	}
	int stk[20], tp;
	template <typename Shiodome_miuna> inline void ot (Shiodome_miuna x, int f = 2)
	{
		if (x < 0) putchar ('-'), x = -x;
		do
		{
			stk[++ tp] = x % 10;
			x /= 10;
		} while (x);
		while (tp)
		{
			putchar (stk[tp --] | 48);
		}
		if (f == 1) putchar ('\n');
		if (!f) putchar (' ');
	}
}using namespace LRH;
typedef long long ll;
random_device seed;
mt19937 sandom (seed ());
inline int min (int a, int b) {return a < b ? a : b;}
const int maxn = 1e5 + 10;
int n, mn, k, tot;
int a[maxn];
struct miuna 
{
	int st[32][maxn];
	void build (void)
	{
		for (int i = 1; i <= n; ++ i) st[0][i] = a[i];
		for (int J = 1; J <= 30; ++ J)
			for (int i = 1; i <= n; ++ i)
			{
				if (i + (1 << J - 1) - 1 > n) break;
				st[J][i] = min (st[J - 1][i], st[J - 1][i + (1 << J - 1)]);
			}
	}
	int qur (int l, int r)
	{
		int LG = log2 (r - l + 1);
		return min (st[LG][l], st[LG][r - (1 << LG) + 1]);
	}
	int query (int l, int r)
	{
		if (r - l + 1 >= n) return qur (1, n);
		int L = (l - 1) / n + 1, R = (r - 1) / n + 1;
		l %= n, r %= n;
		if (!l) l = n;
		if (!r) r = n;
		if (L == R) return qur (l, r);
		return min (qur (l, n), qur (1, r));
	}
}ST;
int t[maxn << 7], lz[maxn << 7], lc[maxn << 7], rc[maxn << 7];
void pushdown (int k, int l, int r)
{
	int mid = l + r >> 1;
	if (!lc[k]) lc[k] = ++ tot, t[lc[k]] = ST.query (l, mid);
	if (!rc[k]) rc[k] = ++ tot, t[rc[k]] = ST.query (mid + 1, r);
	if (!lz[k]) return;
	t[lc[k]] = t[rc[k]] = lz[lc[k]] = lz[rc[k]] = lz[k];
	lz[k] = 0;
}
void update (int k, int l, int r, int L, int R, int v)
{
	if (L <= l && r <= R)
	{
		t[k] = v;
		lz[k] = v;
		return;
	}
	pushdown (k, l, r);
	int mid = l + r >> 1;
	if (L <= mid) update (lc[k], l, mid, L, R, v);
	if (R > mid) update (rc[k], mid + 1, r, L, R, v);
	t[k] = min (t[lc[k]], t[rc[k]]);
}
int query (int k, int l, int r, int L, int R)
{
	if (L <= l && r <= R) return t[k];
	pushdown (k, l, r);
	int mid = l + r >> 1;
	int res = 1209322901;
	if (L <= mid) res = query (lc[k], l, mid, L, R);
	if (R > mid) res = min (res, query (rc[k], mid + 1, r, L, R));
	return res;
}
mizuki main ()
{
	freopen ("data.in", "r", stdin);
	freopen ("data.out", "w", stdout);
	in (n), in (k);
	mn = n * k;
	for (int i = 1; i <= n; ++ i) in (a[i]);
	ST.build ();
	tot = 1;
	t[1] = ST.query (1, n);
	int q, op, l, r, w;
	in (q);
	for (int i = 1; i <= q; ++ i)
	{
		in (op), in (l), in (r);
		if (op == 1)
		{
			in (w);
			update (1, 1, mn, l, r, w);
		}
		else ot (query (1, 1, mn, l, r), 1);
	}
	return love;
	Miuna;
}

信息学的尽头

只因环树+换根\(DP\)
先找出来环,然后把环断成链双指针处理环上每个点的 \(ans\),对环上的每棵树进行换根\(DP\)就彳亍了

AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#include<map>
using namespace std;

#define Miuna printf ("dai  suki...")
#define mizuki signed 
#define love (1209 & 322 & 901)

namespace LRH 
{
	template <typename Shiodome_miuna> inline void in (Shiodome_miuna &x)
	{
		x = 0;
		char f = 0; char ch;
		while (!isdigit (ch = getchar ())) if (ch == '-') f = 1;
		do
		{
			x = (x << 1) + (x << 3) + (ch ^ 48);
		} while (isdigit (ch = getchar ()));
		if (f) x = -x;
	}
	int stk[20], tp;
	template <typename Shiodome_miuna> inline void ot (Shiodome_miuna x, int f = 2)
	{
		if (x < 0) putchar ('-'), x = -x;
		do
		{
			stk[++ tp] = x % 10;
			x /= 10;
		} while (x);
		while (tp)
		{
			putchar (stk[tp --] | 48);
		}
		if (f == 1) putchar ('\n');
		if (!f) putchar (' ');
	}
}using namespace LRH;
typedef long long ll;
const int maxn = 6e5 + 10;
#define int ll
int n, len, cnt;
int a[maxn], b[maxn], s[maxn], siz[maxn], ans[maxn], sum[maxn];
char v[200010];
struct miuna 
{
	int v, nt, w;
}e[maxn << 1];
int tot, head[maxn];
inline void add (int u, int v, int w)
{
	e[++ tot] = {v, head[u], w};
	head[u] = tot;
}
int P;
bool dfs1 (int x, int fa)
{
	v[x] = 1;
	for (int i = head[x]; i; i = e[i].nt)
	{
		int y = e[i].v;
		if (y == fa) continue;
		if (v[y])
		{
			P = y;
			a[++ cnt] = x;
			b[cnt] = e[i].w;
			len += e[i].w;
			return 1;
		}
		if (dfs1 (y, x))
		{
			a[++ cnt] = x;
			b[cnt] = e[i].w;
			len += e[i].w;
			if (x == P) return 0;
			return 1;
		}
	}
	v[x] = 0;
	return 0;
}
void dfs2 (int x, int fa)
{
	siz[x] = 1;
	for (int i = head[x]; i; i = e[i].nt)
	{
		int y = e[i].v;
		if (y == fa || v[y]) continue;
		dfs2 (y, x);
		sum[x] += e[i].w * siz[y] + sum[y];
		siz[x] += siz[y];
	}
}
void dfs3 (int x, int fa)
{
	for (int i = head[x]; i; i = e[i].nt)
	{
		int y = e[i].v;
		if (y == fa || v[y]) continue;
		ans[y] = ans[x] + (n - siz[y]) * e[i].w - siz[y] * e[i].w;
		dfs3 (y, x);
	}
}
mizuki main ()
{
	freopen ("end.in", "r", stdin);
	freopen ("end.out", "w", stdout);
	in (n);
	for (int i = 1, x, y, z; i <= n; ++ i) 
	{
		in (x), in (y), in (z);
		add (x, y, z);
		add (y, x, z);
	}
	dfs1 (1, 0);
	for (int i = 1; i <= cnt << 1; ++ i) a[i + cnt] = a[i], b[i + cnt] = b[i], s[i] = s[i - 1] + b[i];
	memset (v, 0, sizeof (v));
	for (int i = 1; i <= cnt; ++ i) v[a[i]] = 1;
	for (int i = 1; i <= cnt; ++ i) dfs2 (a[i], 0);
	ll tmp = 0;
	for (int i = 1; i <= cnt; ++ i) tmp += sum[a[i]] + min (len - (s[cnt + 1] - s[i]), s[cnt + 1] - s[i]) * siz[a[i]];
	for (int i = 2; i <= cnt + 1; ++ i)
	{
		if (s[cnt + 1] - s[i] <= len - (s[cnt + 1] - s[i]))
		{
			P = i;
			break;
		}
	}
	ll res = 0;
	for (int i = P; i <= cnt + 1; ++ i) res += siz[a[i]];
	for (int i = cnt + 1; i <= cnt << 1; ++ i)
	{
		if (i != cnt + 1)
		{
			tmp += res * b[i];
			tmp -= (n - res) * b[i];
			res += siz[a[i]];
			while (P <= i && s[i] - s[P] >= len - (s[i] - s[P]))
			{
				tmp -= (s[i] - s[P]) * siz[a[P]];
				res -= siz[a[P]];
				tmp += (len - (s[i] - s[P])) * siz[a[P]];
				P ++;
			}
		}
		ans[a[i]] = tmp;
	}
	for (int i = 1; i <= cnt; ++ i) dfs3 (a[i], 0);
	for (int i = 1; i <= n; ++ i) ot (ans[i], 0);
	return love;
}

球对称薛定谔方程

容易看出如果向\(A\)中在位置\(J\)和位置\(J-1\)中间插入一个新的元素,那么这个元素应该大于等于\(A_J\)
然而这样会出现重复,因此可以强制插入的元素严格大于\(A_J\)就可以避免重复了,从小到大放每个数
\(dp_{i, J, k}\) 表示当前长度为 \(i\),当前位置放 \(J\),后面还有 \(k\) 个位置没有决定放的方案数
转移:

\(dp_{i, J, k-1} \leftarrow dp_{i, J, k}\) 不再往当前位置放 \(J\),后面决定放的位置减一
\(dp_{i, J+1, i} \leftarrow dp_{i, J, 0}\) 没有可以放的位置了,考虑下一个\(J\)
\(dp_{i+1, J, k} \leftarrow dp_{i, J, k} × (k + 1)\) 在当前位置放一个 \(J\)\(k\) 不变是因为 \(J\) 的后面还可以再放

初始状态 \(dp_{1, i, 0} = 1 (i ∈ [1 , k])\)
答案即为 \(dp_{n, k, 0}\).

AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<deque>
using namespace std;

#define Miuna printf ("dai  suki...")
#define mizuki signed 
#define love (1209 & 322 & 901)

namespace LRH 
{
	template <typename Shiodome_miuna> inline void in (Shiodome_miuna &x)
	{
		x = 0;
		char f = 0; char ch;
		while (!isdigit (ch = getchar ())) if (ch == '-') f = 1;
		do
		{
			x = (x << 1) + (x << 3) + (ch ^ 48);
		} while (isdigit (ch = getchar ()));
		if (f) x = -x;
	}
	int stk[20], tp;
	template <typename Shiodome_miuna> inline void ot (Shiodome_miuna x, int f = 2)
	{
		if (x < 0) putchar ('-'), x = -x;
		do
		{
			stk[++ tp] = x % 10;
			x /= 10;
		} while (x);
		while (tp)
		{
			putchar (stk[tp --] | 48);
		}
		if (f == 1) putchar ('\n');
		if (!f) putchar (' ');
	}
}using namespace LRH;
typedef long long ll;
const int maxn = 3e2 + 10;
#define int ll
int n, k, mod, ans;
int a[maxn], f[maxn][maxn][maxn];
mizuki main ()
{
	freopen ("seq.in", "r", stdin);
	freopen ("seq.out", "w", stdout);
	in (n), in (k), in (mod);
	for (int i = 1; i <= k; ++ i) f[1][i][0] = 1;
	for (int i = 1; i <= n; ++ i)
	{
		for (int J = 1; J <= k; ++ J)
		{
			for (int K = i; K >= 0; -- K)
			{
				if (K > 0) (f[i][J][K - 1] += f[i][J][K]) %= mod;
				(f[i + 1][J][K] += f[i][J][K] * (K + 1) % mod) %= mod;
			}
			(f[i][J + 1][i] += f[i][J][0]) %= mod;
		}
	}
	ot (f[n][k][0]);
	return love;
}
posted @ 2022-11-13 21:11  _Mizuki  阅读(21)  评论(4编辑  收藏  举报