pyyz集训day6

课件:https://files.cnblogs.com/files/blogs/832279/8.12动态规划选讲.zip?t=1786495942&download=true
献上代码:

1.Slastičarnica

点击查看代码
#include <iostream>

using std::cin;
using std::cout;
const int N = 5e3 + 10;
const int oo = 1e9 + 10;

int pos;
int a[N];
int nxt[N];
int pre[N];
int f[N][N];
int mn[N][N];

int main()
{
	int n, q;
	cin >> n >> q;
	for (int i = 1; i <= n; ++i)
		cin >> a[i];
	for (int i = 1; i <= n; ++i)
	{
		mn[i][i - 1] = oo;
		for (int j = i; j <= n; ++j)
			mn[i][j] = std::min(mn[i][j - 1], a[j]);
	}
	for (int i = 1; i <= n; ++i)
		f[0][i] = n;
	for (int i = 1; i <= q; ++i)
	{
		for (int j = 1; j <= n; ++j)
			f[i][j] = -oo;
		int d, s;
		cin >> d >> s;
		pos = oo;
		for (int j = n; j >= 1; --j)
		{
			if (j + d - 1 <= n && mn[j][j + d - 1] >= s)
				pos = j;
			nxt[j] = pos;
		}
		pos = -oo;
		for (int j = 1; j <= n; ++j)
		{
			if (j - d + 1 > 0 && mn[j - d + 1][j] >= s)
				pos = j;
			pre[j] = pos;
		}
		for (int j = 1; j <= n; ++j)
		{
			if (nxt[j] + d <= n)
				f[i][nxt[j] + d] = std::max(f[i][nxt[j] + d], f[i - 1][j]);
			if (f[i - 1][j] > 0)
				f[i][j] = std::max(f[i][j], pre[f[i - 1][j]] - d);
		}
		bool fl = false;
		for (int j = 1; j <= n; ++j)
		{
			if (f[i][j] >= j - 1)
			{
				fl = true;
				break;
			}
		}
		if (!fl)
		{
			cout << i - 1 << '\n';
			return 0;
		}
	}
	cout << q << '\n';
	return 0;
}

2.AND Segments

点击查看代码
#include <iostream>
 
using std::cin;
using std::cout;
const int N = 5e5 + 10;
 
const int mod = 998244353;
struct Node
{
	int l, r;
	friend bool operator<(const Node &a, const Node &b)
	{
		return (a.l ^ b.l ? a.l < b.l : a.r < b.r);
	}
} z[N << 2];
 
int f[N];
int c0[N];
int c1[N];
int n0[N];
int n1[N];
int l[N];
int r[N];
int x[N];
int mxl[N];
 
int main()
{
	int n, k, m;
	cin >> n >> k >> m;
	for (int i = 1; i <= m; ++i)
		cin >> l[i] >> r[i] >> x[i];
	int ans = 1;
	for (int i = 0; i < k; ++i)
	{
		for (int j = 1; j <= n; ++j)
			mxl[j] = c0[j] = c1[j] = f[j] = 0;
		for (int j = 1; j <= m; ++j)
		{
			int nx = (x[j] >> i) & 1;
			if (nx)
				c1[l[j]]++, c1[r[j] + 1]--;
			else
				c0[l[j]]++, c0[r[j] + 1]--, mxl[r[j]] = std::max(mxl[r[j]], l[j]);
		}
		int k = -1;
		int pos = 0;
		int sum = 1;
		f[0] = 1;
		for (int j = 1; j <= n; ++j)
		{
			n0[j] = n0[j - 1] + c0[j];
			n1[j] = n1[j - 1] + c1[j];
			if (mxl[j])
				pos = std::max(pos, mxl[j]);
			while (pos <= n && n1[pos])
				pos++;
			if (pos <= j)
			{
				if (n1[j])
					f[j] = 0;
				else
					f[j] = sum, sum = (sum + f[j]) % mod;
			}
			while (k + 1 < pos)
				k++, sum = ((sum - f[k]) % mod + mod) % mod, f[k] = 0;
		}
		ans = 1ll * ans * sum % mod;
	}
	cout << ans << '\n';
	return 0;
}

3.The Maximum Prefix

点击查看代码
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
#define pii std::pair<int, int>

using std::cin;
using std::cout;
const int N = 5e3 + 10;
const int mod = 1e9 + 7;

int ni(int x)
{
	int k = mod - 2;
	int ret = 1;
	for (; k; x = 1ll * x * x % mod, k >>= 1)
	{
		if (k & 1)
			ret = 1ll * ret * x % mod;
	}
	return ret;
}

int n;
int h[N];
int p[N];
int g[N * N];
int deg[N * N];
std::queue<int> q;

int pt(int x, int k)
{
	return (x - 1) * (n + 1) + k;
}

int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(nullptr);
	int t;
	cin >> t;
	while (t--)
	{
		cin >> n;
		for (int i = 1; i <= n; ++i)
		{
			int x, y;
			cin >> x >> y;
			p[i] = 1ll * x * ni(y) % mod;
		}
		for (int i = 0; i <= n; ++i)
			cin >> h[i];
		for (int i = 1; i <= n + 1; ++i)
		{
			for (int j = 0; j <= n; ++j)
			{
				int now = pt(i, j);
				g[now] = 0;
				if (i == 1)
				{
					deg[now] = 0;
					continue;
				}
				if (j == n)
					deg[now] = 1;
				else
					deg[now] = 2;
			}
		}
		for (int i = 0; i <= n; ++i)
			g[pt(1, i)] = h[i], q.push(pt(1, i));
		while (q.size())
		{
			int now = q.front();
			q.pop();
			int i = now / (n + 1) + 1;
			if (i == n + 1)
				continue;
			int j = now % (n + 1);
			int to;
			if (j >= 1)
			{
				to = pt(i + 1, j - 1);
				g[to] = (g[to] + 1ll * p[i] * g[now] % mod) % mod;
				deg[to]--;
				if (!deg[to])
					q.push(to);
			}
			if (j < n)
			{
				to = pt(i + 1, j + 1);
				g[to] = (g[to] + 1ll * (1 - p[i] + mod) * g[now] % mod) % mod;
				deg[to]--;
				if (!deg[to])
					q.push(to);
			}
			if (j == 0)
			{
				to = pt(i + 1, 0);
				g[to] = (g[to] + 1ll * g[now] * (1 - p[i] + mod) % mod) % mod;
				deg[to]--;
				if (!deg[to])
					q.push(to);
			}
		}
		for (int i = 1; i <= n; ++i)
			cout << g[pt(i + 1, 0)] << ' ';
		cout << '\n';
	}
	return 0;
}

ps:这个题不能显式建边,会MLE

4.Magneti

点击查看代码
#include <iostream>
#include <algorithm>

using std::cin;
using std::cout;
const int N = 60;
const int M = 1e4 + 10;
const int mod = 1e9 + 7;

int r[N];
int fac[N + M];
int ifac[N + M];
int inv[N + M];
int f[N][N][M];

int C(int n, int m)
{
	return 1ll * fac[n] * ifac[m] % mod * ifac[n - m] % mod;
}

int main()
{
	int n, l;
	cin >> n >> l;
	for (int i = 1; i <= n; ++i)
		cin >> r[i];
	inv[1] = 1;
	ifac[0] = fac[0] = 1;
	for (int i = 1; i <= l + n; ++i)
	{
		if (i > 1)
			inv[i] = 1ll * (-mod / i + mod) * inv[mod % i] % mod;
		ifac[i] = 1ll * ifac[i - 1] * inv[i] % mod;
		fac[i] = 1ll * fac[i - 1] * i % mod;
	}
	std::sort(r + 1, r + n + 1);
	f[0][0][0] = 1;
	for (int i = 1; i <= n; ++i)
	{
		for (int j = 0; j <= n; ++j)
		{
			for (int k = 0; k <= l; ++k)
			{
				if (j < n && k + 1 <= l)
					f[i][j + 1][k + 1] = (f[i][j + 1][k + 1] + f[i - 1][j][k]) % mod;
				if (k + r[i] <= l)
					f[i][j][k + r[i]] = (f[i][j][k + r[i]] + 2ll * j % mod * f[i - 1][j][k] % mod) % mod;
				if (k + 2 * r[i] - 1 <= l && j > 1)
					f[i][j - 1][k + 2 * r[i] - 1] = (f[i][j - 1][k + 2 * r[i] - 1] + 1ll * j * (j - 1) % mod * f[i - 1][j][k] % mod) % mod;
			}
		}
	}
	int ans = 0;
	for (int i = 0; i <= l; ++i)
		ans = (ans + 1ll * C(n + l - i, n) * f[n][1][i] % mod) % mod;
	cout << ans << '\n';
	return 0;
}

5.Simple Speed

点击查看代码
#include <iostream>
#include <unordered_map>

using std::cin;
using std::cout;
const int N = 2e5 + 10;
const int mod = 998244353;

int a[N];
int inv[N];
int fac[N];
int ifac[N];
std::unordered_map<int, int> f[N][3];

int C(int n, int m)
{
	return 1ll * fac[n] * ifac[n - m] % mod * ifac[m] % mod;
}

int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; ++i)
		cin >> a[i];
	f[0][0][0] = 1;
	inv[1] = 1;
	fac[0] = ifac[0] = 1;
	for (int i = 1; i <= 2e5; ++i)
	{
		if (i > 1)
			inv[i] = 1ll * inv[mod % i] * (-mod / i + mod) % mod;
		fac[i] = 1ll * fac[i - 1] * i % mod;
		ifac[i] = 1ll * ifac[i - 1] * inv[i] % mod;
	}
	for (int i = 1; i <= n; ++i)
	{
		for (auto now : f[i - 1][0])
		{
			int j = now.first;
			int val = now.second;
			int k = a[i] - j - 1;
			if (k < 0)
				continue;
			f[i][0][k + 1] = (f[i][0][k + 1] + 1ll * val * C(k + j, j) % mod) % mod;
			f[i][1][k + 1] = (f[i][1][k + 1] + 2ll * val * C(k + j, j) % mod) % mod;
			f[i][2][k + 1] = (f[i][2][k + 1] + 1ll * val * C(k + j, j) % mod) % mod;
		}
		for (auto now : f[i - 1][1])
		{
			int j = now.first;
			if (j < 1)
				continue;
			int val = now.second;
			int k = a[i] - j;
			if (k < 0)
				continue;
			f[i][1][k + 1] = (f[i][1][k + 1] + 1ll * val * C(k + j - 1, j - 1) % mod) % mod;
			f[i][2][k + 1] = (f[i][2][k + 1] + 1ll * val * C(k + j - 1, j - 1) % mod) % mod;
		}
		for (auto now : f[i - 1][2])
		{
			int j = now.first;
			if (j < 2)
				continue;
			int val = now.second;
			int k = a[i] - j + 1;
			if (k < 0)
				continue;
			f[i][2][k + 1] = (f[i][2][k + 1] + 1ll * val * C(k + j - 2, j - 2) % mod) % mod;
		}
	}
	cout << f[n][2][1] << '\n';
	return 0;
}

ps:这个题没太搞懂老师的式子,就自己推了一些相似的式子,其中 \(k\) 表示还有多少可以随便放的 \(i\)

6.Robot and String

点击查看代码
#include <iostream>
#include <string>

using std::cin;
using std::cout;
const int N = 5e5 + 10;
const int M = 30;

int f[N][27];
int nxt[N][21];

int main()
{
	std::string s;
	cin >> s;
	int n = s.size();
	s = ' ' + s;
	for (int i = 1; i <= n; ++i)
		f[i][s[i] - 'a'] = i;
	for (int i = n; i >= 1; --i)
	{
		for (int j = s[i] - 'a' + 1; j <= 26; ++j)
			f[i][j] = (f[i][j - 1] ? f[f[i][j - 1] + 1][j - 1] : 0);
		for (int j = 0; j < s[i] - 'a'; ++j)
			f[i][j] = (f[i][26] ? f[f[i][26] + 1][j] : 0);
		nxt[i][0] = f[i][26];
	}
	for (int i = 1; i <= 20; ++i)
	{
		for (int j = 1; j <= n; ++j)
			nxt[j][i] = (nxt[j][i - 1] ? nxt[nxt[j][i - 1] + 1][i - 1] : 0);
	}
	int q;
	cin >> q;
	while (q--)
	{
		int l, r;
		cin >> l >> r;
		int x = l;
		for (int i = 20; i >= 0; --i)
		{
			if (nxt[x][i] && nxt[x][i] <= r)
				x = nxt[x][i] + 1;
		}
		if (x == r + 1)
			cout << "Yes" << '\n';
		else
			cout << "No" << '\n';
	}
	return 0;
}

ps:一定要处理好边界情况(无法到达的状态)!!!

7.魔法值

点击查看代码
#include <iostream>
#include <cstring>
#define int long long 

using std::cin;
using std::cout;
const int N = 100 + 10;
const int M = 31 + 5;
typedef long long ll;
struct Mat
{
	int n, m;
	ll c[N][N];
	Mat()
	{
		memset(c, 0, sizeof(c));
	}
	void init(int x)
	{
		memset(c, 0, sizeof(c));
		n = m = x;
		for (int i = 1; i <= x; ++i)
			c[i][i] = 1;
	}
	friend Mat operator*(const Mat &a, const Mat &b)
	{
		Mat ret;
		ret.n = a.n;
		ret.m = b.m;
		for (int i = 1; i <= a.n; ++i)
		{
			for (int j = 1; j <= a.m; ++j)
			{
				for (int k = 1; k <= b.m; ++k)
					ret.c[i][k] ^= 1ll * a.c[i][j] * b.c[j][k];
			}
		}
		return ret;
	}
};

Mat fst;
Mat chu;
int a[N];
Mat e[M];

signed main()
{
	int n, m, q;
	cin >> n >> m >> q;
	fst.n = n, fst.m = 1;
	for (int i = 1; i <= n; ++i)
		cin >> fst.c[i][1];
	for (int i = 0; i <= 31; ++i)
		e[i].n = e[i].m = n;
	for (int i = 1; i <= m; ++i)
	{
		int u, v;
		cin >> u >> v;
		e[0].c[u][v] = e[0].c[v][u] = 1;
	}
	for (int i = 1; i <= 31; ++i)
		e[i] = e[i - 1] * e[i - 1];
	for (int i = 1; i <= q; ++i)
	{
		chu = fst;
		int a;
		cin >> a;
		for (int j = 31; j >= 0; --j)
		{
			if ((a >> j) & 1)
				chu = e[j] * chu;
		}
		cout << chu.c[1][1] << '\n';
	}
	return 0;
}

8.花神诞日 / sabzeruz

点击查看代码
#include <iostream>
#include <algorithm>

using std::cin;
using std::cout;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
typedef long long ll;

int tot[2] = {1, 1};
ll a[N];
bool tag[2][N * 180];
int sum[2][N * 180];
int son[2][N * 180][2];

void push_down(int p, int s)
{
	if (tag[s][p])
	{
		if (!son[s][p][0])
			son[s][p][0] = ++tot[s];
		if (!son[s][p][1])
			son[s][p][1] = ++tot[s];
		sum[s][son[s][p][0]] = sum[s][son[s][p][1]] = 0;
		tag[s][son[s][p][0]] = tag[s][son[s][p][1]] = true;
		tag[s][p] = false;
	}
}
void modiadd(int b, int p, ll x, int v, int s)
{
	if (b == -1)
	{
		sum[s][p] = (sum[s][p] + v) % mod;
		return;
	}
	push_down(p, s);
	int k = (x >> b) & 1;
	if (!son[s][p][k])
		son[s][p][k] = ++tot[s];
	modiadd(--b, son[s][p][k], x, v, s);
	sum[s][p] = (sum[s][son[s][p][0]] + sum[s][son[s][p][1]]) % mod;
}
int query(ll ai, ll ks, int s)
{
	int now = 1;
	int ret = 0;
	for (int i = 60; i >= 0; --i)
	{
		if (!now)
			return ret;
		push_down(now, s);
		int k = (ks >> i) & 1;
		int t = (ai >> i) & 1;
		if (!k)
		{
			ret = (ret + sum[s][son[s][now][t ^ 1]]) % mod;
			now = son[s][now][t];
		}
		else
			now = son[s][now][t ^ 1];
	}
	return (ret + sum[s][now]) % mod;
}

int main()
{
	ll k[2];
	int v[2];
	int n;
	cin >> n >> k[0] >> k[1];
	if (n == 1)
	{
		cout << 0 << '\n';
		return 0;
	}
	for (int i = 1; i <= n; ++i)
		cin >> a[i];
	std::sort(a + 1, a + n + 1);
	modiadd(60, 1, 1ll << 60, 1, 0);
	modiadd(60, 1, 1ll << 60, 1, 1);
	for (int i = 1; i <= n; ++i)
	{
		if (i == 1)
			continue;
		for (int s = 0; s <= 1; ++s)
			v[s] = query(a[i], k[s], s ^ 1);
		for (int s = 0; s <= 1; ++s)
		{
			if ((a[i] ^ a[i - 1]) < k[s])
			{
				tag[s][1] = true;
				sum[s][1] = 0;
			}
		}
		for (int s = 0; s <= 1; ++s)
			modiadd(60, 1, a[i - 1], v[s], s);
	}
	bool f1 = true, f2 = true;
	for (int i = 1; i < n; ++i)
	{
		if ((a[i - 1] ^ a[i]) < k[0])
			f1 = false;
		if ((a[i - 1] ^ a[i]) < k[1])
			f2 =  false;
	}
	cout << ((sum[0][1] + sum[1][1] - f1 - f2) % mod + mod) % mod << '\n';
	return 0;
}

ps1:一定要考虑所有东西都分在一组的情况,这种情况不合法,但会被统计入答案!!!
ps2:似乎像我这么写并不是最好的,会占用超大空间,因为是全局清除,所以可以直接让trie的tot变回1,每次新加入一个点的时候将其所有信息(除编号)都赋值为 \(0\) 即可。

9.Adam and Tree

点击查看代码
#include <iostream>

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

int p[N];
int mx[N];
int idmx[N];
int sec[N];
int ans[N];
int son[N];

int main()
{
	int n;
	cin >> n;
	for (int i = 1; i <= n; ++i)
		cin >> p[i + 1];
	p[1] = 0;
	for (int i = 1; i <= n; ++i)
	{
		int to = i + 1;
		ans[to] = 1;
		son[p[i + 1]]++;
		while (to != 1)
		{
			int x = p[to];
			if (mx[x] < ans[to] || !idmx[x])
			{
				if (idmx[x] != to)
					sec[x] = mx[x];
				mx[x] = ans[to];
				idmx[x] = to;
			}
			else if (idmx[x] != to)
				sec[x] = std::max(sec[x], ans[to]);
			if (ans[x] < (son[x] > 1 ? std::max(sec[x] + (x != 1), mx[x]) : mx[x]))
			{
				ans[x] = (son[x] > 1 ? std::max(sec[x] + (x != 1), mx[x]) : mx[x]);
				to = x;
			}
			else
				break;
		}
		cout << ans[1] << ' ';
	}
	cout << '\n';
	return 0;
}

ps:如果维护当前点的ans的不算上当前点到父亲的边,似乎有点难维护(?)

10.Watching Cowflix P

点击查看代码
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>

using std::cin;
using std::cout;
const int N = 2e5 + 10;
const int G = 21;
const int M = 510;
typedef long long ll;
const ll oo = 1e13;

int n;
int m;
int k;
int B;
int idx;
bool is[N];
int ws[N];
int id[N];
int re[N];
int dfn[N];
int siz[N];
ll f[N][2];
ll g[G][M][2];
std::vector<int> e[N];

void dfs(int x, int fa)
{
	dfn[x] = ++idx;
	re[idx] = x;
	for (auto to : e[x])
	{
		if (to == fa)
			continue;
		dfs(to, x);
	}
	siz[x] = 1;
	for (auto to : e[x])
	{
		if (to == fa)
			continue;
		siz[x] += siz[to];
		if (siz[to] > siz[ws[x]])
			ws[x] = to;
	}
}
void dp2(int x, int fa)
{
	int pre;
	if (ws[x])
	{
		id[ws[x]] = id[x];
		dp2(ws[x], x);
		pre = siz[ws[x]] + 1;
		for (int i = std::min(m, pre); i >= 0; --i)
		{
			ll a = oo, b = oo;
			if (i >= 1)
				a = g[id[x]][i - 1][0] + 1;
			if (i <= std::min(m, siz[ws[x]]))
				b = g[id[x]][i][1] + 1;
			g[id[x]][i][0] = std::min(g[id[x]][i][0], g[id[x]][i][1]);
			g[id[x]][i][1] = std::min(a, b);
		}
	}
	else
	{
		pre = 1;
		g[id[x]][1][1] = 1;
		g[id[x]][0][0] = (is[x] ? oo : 0);
	}
	for (auto to : e[x])
	{
		if (to == fa || to == ws[x])
			continue;
		id[to] = id[x] + 1;
		for (int i = 0; i <= m; ++i)
			g[id[to]][i][0] = g[id[to]][i][1] = oo;
		dp2(to, x);
		pre += siz[to];
		for (int i = std::min(m, pre); i >= 0; --i)
		{
			ll now0 = oo;
			ll now1 = oo;
			for (int j = 0; j <= std::min({m, siz[to], i}); ++j)
			{
				now0 = std::min({now0, g[id[x]][i - j][0] + g[id[to]][j][0], g[id[x]][i - j][0] + g[id[to]][j][1]});
				ll a = g[id[x]][i - j][1] + g[id[to]][j][0];
				ll b = oo, c = oo;
				if (j >= 1)
					b = g[id[x]][i - j + 1][1] + g[id[to]][j][1];
				if (i - j >= 1 && j + 1 <= std::min(m, siz[to]))
					c = g[id[x]][i - j][1] + g[id[to]][j + 1][1];
				now1 = std::min({now1, a, b, c});
			}
			g[id[x]][i][0] = now0;
			g[id[x]][i][1] = now1;
		}
	}
	if (is[x])
	{
		for (int i = 0; i <= m; ++i)
			g[id[x]][i][0] = oo;
	}
}
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)
	{
		char c;
		cin >> c;
		is[i] = c - '0';
	}
	for (int i = 1; i < n; ++i)
	{
		int u, v;
		read(u), read(v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	B = sqrt(n);
	m = (n + B - 1) / B;
	dfs(1, 0);
	for (int i = 1; i <= B; ++i)
	{
		for (int j = idx; j >= 1; --j)
		{
			if (is[re[j]])
				f[j][0] = oo;
			else
				f[j][0] = 0;
			f[j][1] = i + 1;
			for (auto to : e[re[j]])
			{
				if (dfn[to] < j)
					continue;
				to = dfn[to];
				f[j][1] = std::min(f[j][1] + f[to][0], f[j][1] + f[to][1] - i);
				f[j][0] = std::min(f[j][0] + f[to][0], f[j][0] + f[to][1]);
			}
		}
		cout << std::min(f[1][1], f[1][0]) << '\n';
	}
	for (int j = 0; j <= m; ++j)
		g[0][j][0] = g[0][j][1] = oo;
	dp2(1, 0);
	for (int i = B + 1; i <= n; ++i)
	{
		ll ans = oo;
		for (int j = 0; j <= m; ++j)
			ans = std::min(ans, std::min(g[0][j][0], g[0][j][1]) + 1ll * i * j);
		cout << ans << '\n';
	}
	return 0;
}

ps1:关于MLE的问题,参考了 https://www.luogu.com.cn/article/xaeo6kmz
ps2:关于TLE问题,只需预处理dfs序,并将第一个树形dp放在dfs序上维护即可。

11.friend 朋友

点击查看代码

const int N = 1e5 + 10;

long long f[N][2];

long long max(long long x, long long y)
{
	return (x < y ? y : x);
}

long long findSample(int n, int confidence[], int host[], int protocol[])
{
	for (int i = 0; i < n; ++i)
		f[i][0] = 0, f[i][1] = confidence[i];
	for (int i = n - 1; i >= 1; --i)
	{
		int x = i;
		int y = host[i];
		if (protocol[i] == 0)
			f[y][0] = f[y][0] + max(f[x][0], f[x][1]), f[y][1] = f[y][1] + f[x][0];
		else if (protocol[i] == 1)
			f[y][1] = max(f[y][1] + max(f[x][0], f[x][1]), f[y][0] + f[x][1]), f[y][0] = f[y][0] + f[x][0];
		else
			f[y][1] = max(f[y][1] + f[x][0], f[y][0] + f[x][1]), f[y][0] = f[y][0] + f[x][0];
	}
	return max(f[0][0], f[0][1]);
}

ps1:一定不能改变函数参数的类型,这也是define int long long会CE的原因;其次,不建议改变函数的返回值类型,请严格遵守题目中的要求,不要学我!!!
ps2:请注意dp的顺序,第二三种不要先更新f[y][0]。

12.Rolling Hash

点击查看代码
#include <iostream>
#include <vector>

using std::cin;
using std::cout;
const int N = 20;
const int inf = 1e9 + 10;

bool isd[1 << N];
int f[1 << N];
std::vector<int> e[N];

int main()
{
	int p, b, n, m;
	cin >> p >> b >> n >> m;
	if (p > n)
	{
		cout << "Yes" << '\n';
		return 0;
	}
	for (int i = 1; i <= m; ++i)
	{
		int l, r;
		cin >> l >> r;
		e[l].push_back(r + 1);
	}
	for (int i = 0; i < (1 << (n + 1)); ++i)
		f[i] = inf;
	f[0] = 0;
	for (int i = 0; i < (1 << (n + 1)); ++i)
	{
		bool f = true;
		for (int k = 1; k <= n; ++k)
		{
			if (!((i >> (k - 1)) & 1))
				continue;
			for (int j : e[k])
			{
				if ((i >> (j - 1)) & 1)
				{
					f = false;
					break;
				}
			}
			if (!f)
				break;
		}
		isd[i] = f;
	}
	for (int i = 1; i < (1 << (n + 1)); ++i)
	{
		for (int j = (i - 1) & i; j; j = (j - 1) & i)
		{
			if (isd[j])
				f[i] = std::min(f[i], f[i ^ j] + 1);
		}
		if (isd[i])
			f[i] = std::min(f[i], 1);
	}
	if (f[(1 << (n + 1)) - 1] <= p)
		cout << "Yes" << '\n';
	else
		cout << "No" << '\n';
	return 0;
}

13.寿司晚宴

点击查看代码
#include <iostream>
#include <vector>

using std::cin;
using std::cout;
const int N = 510;
const int M = (1 << 9) + 10;

std::vector<int> num[N];
int s[N];
int pr[N];
int ex[N];
int g[M];
int f[2][M][M];

bool is(int x)
{
	if (x == 1)
		return false;
	for (int i = 2; i * i <= x; ++i)
	{
		if (x % i == 0)
			return false;
	}
	return true;
}

int main()
{
	int n, p;
	cin >> n >> p;
	int tot = 0;				
	for (int i = 1; i <= 21; ++i)
	{
		if (is(i))
			pr[++tot] = i;
	}
	for (int i = 2; i <= n; ++i)
	{
		int ni = i;
		for (int j = 1; j <= tot; ++j)
		{
			while (ni % pr[j] == 0)
				s[i] |= (1 << (j - 1)), ni /= pr[j];
		}
		if (ni != 1)
			ex[i] = ni, num[ni].push_back(s[i]);
	}
	int c = 0;
	f[0][0][0] = 1;
	for (int i = 2; i <= n; ++i)
	{
		if (ex[i])
			continue;
		for (int j = 0; j < (1 << tot); ++j)
		{
			for (int k = ((1 << tot) - 1) ^ j; k; k = (k - 1) & (((1 << tot) - 1) ^ j))
				f[c ^ 1][j][k] = f[c][j][k];
			f[c ^ 1][j][0] = f[c][j][0];
		}
		for (int j = 0; j < (1 << tot); ++j)
		{
			for (int k = ((1 << tot) - 1) ^ j; k; k = (k - 1) & (((1 << tot) - 1) ^ j))
			{
				if (!(s[i] & k))
					f[c ^ 1][j | s[i]][k] = (f[c ^ 1][j | s[i]][k] + f[c][j][k]) % p;
				if (!(s[i] & j))
					f[c ^ 1][j][k | s[i]] = (f[c ^ 1][j][k | s[i]] + f[c][j][k]) % p;
			}
			int k = 0;
			if (!(s[i] & k))
				f[c ^ 1][j | s[i]][k] = (f[c ^ 1][j | s[i]][k] + f[c][j][k]) % p;
			if (!(s[i] & j))
				f[c ^ 1][j][k | s[i]] = (f[c ^ 1][j][k | s[i]] + f[c][j][k]) % p;
		}
		c ^= 1;
	}
	for (int i = 22; i <= 500; ++i)
	{
		g[0] = 1;
		for (int k = 1; k < (1 << tot); ++k)
			g[k] = 0;
		for (auto j : num[i])
		{
			for (int k = (1 << tot) - 1; k >= 0; --k)
				g[k | j] = (g[k | j] + g[k]) % p;
		}
		g[0]--;
		for (int j = 0; j < (1 << tot); ++j)
		{
			for (int k = ((1 << tot) - 1) ^ j; k; k = (k - 1) & (((1 << tot) - 1) ^ j))
				f[c ^ 1][j][k] = f[c][j][k];
			f[c ^ 1][j][0] = f[c][j][0];
		}
		for (int i = 0; i < (1 << tot); ++i)
		{
			if (!g[i])
				continue;
			for (int j = 0; j < (1 << tot); ++j)
			{
				for (int k = ((1 << tot) - 1) ^ j; k; k = (k - 1) & (((1 << tot) - 1) ^ j))
				{
					if (!(i & k))
						f[c ^ 1][j | i][k] = (f[c ^ 1][j | i][k] + 1ll * g[i] * f[c][j][k] % p) % p;
					if (!(i & j))
						f[c ^ 1][j][k | i] = (f[c ^ 1][j][k | i] + 1ll * g[i] * f[c][j][k] % p) % p;
				}
				int k = 0;
				if (!(i & k))
					f[c ^ 1][j | i][k] = (f[c ^ 1][j | i][k] + 1ll * g[i] * f[c][j][k] % p) % p;
				if (!(i & j))
					f[c ^ 1][j][k | i] = (f[c ^ 1][j][k | i] + 1ll * g[i] * f[c][j][k] % p) % p;
			}
		}
		c ^= 1;
	}
	int ans = 0;
	for (int i = 0; i < (1 << tot); ++i)
	{
			for (int j = ((1 << tot) - 1) ^ i; j; j = (j - 1) & (((1 << tot) - 1) ^ i))
				ans = (ans + f[c][i][j]) % p;
			ans = (ans + f[c][i][0]) % p;
	}
	cout << ans << '\n';
	return 0;
}
posted @ 2026-08-12 08:53  SigmaToT  阅读(28)  评论(0)    收藏  举报