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