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;
}

浙公网安备 33010602011771号