重庆八中集训 day8
20220623
post
题意
给你一个有边权的节点数 \(N\) 树,然后树上 \(M\) 个关键点(可以重复),然后你标记树上的 \(K\) 个点(\(K\) 是你选的),每标记一个点你需要花费 \(C\) 的代价,然后每个关键点会寻找一个离他最近的标记点,代价是它们之间的距离,求你花费的代价的最小值。
数据范围 \(C, w\le 10 ^ 9, N\le 3\times 10 ^ 3\)
题解
看起来就很 \(N ^ 2\) 解决的样子,直接考虑 dp 解决即可,我们令 \(f_{i, j}\) 表示 \(i\) 子树内有 \(j\) 个关键点没有找到自己的点时候的花费(这 \(j\) 个点到 \(i\) 的花费也要算),然后 \(g_{i, j}\) 表示 \(i\) 子树里面自己搞得很好啊,但是从外面进来的关键点匹配进来是跟 \(j\) 匹配的,这种状态的花费。
那么答案就是 \(f_{1, 0}\)。
我们考虑就按照这个意思,转移很平凡,首先考虑怎么合并两个子树,然后考虑假如当前的节点,就是这个节点是不是要加入即可。
// Siriqwq
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::copy;
using std::reverse;
using std::sort;
using std::get;
using std::unique;
using std::swap;
using std::array;
using std::cerr;
using std::function;
using std::map;
using std::set;
using std::pair;
using std::mt19937;
using std::make_pair;
using std::tuple;
using std::make_tuple;
using std::uniform_int_distribution;
using ll = long long;
namespace qwq {
mt19937 eng;
void init(int Seed) {return eng.seed(Seed);}
int rnd(int l = 1, int r = 1000000000) {return uniform_int_distribution<int> (l, r)(eng);}
}
template<typename T>
inline void chkmin(T &x, T y) {if (x > y) x = y;}
template<typename T>
inline void chkmax(T &x, T y) {if (x < y) x = y;}
template<typename T>
inline T min(const T &x, const T &y) {return x < y ? x : y;}
template<typename T>
inline T max(const T &x, const T &y) {return x > y ? x : y;}
char buf[100000], *bufs, *buft;
#define gc() ((bufs == buft && (buft = (bufs = buf) + fread(buf, 1, 100000, stdin))), bufs == buft ? -1 : *bufs++)
template<typename T>
inline void read(T &x) {
x = 0;
bool f = 0;
char ch = gc();
while (!isdigit(ch)) f = ch == '-', ch = gc();
while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
if (f) x = -x;
}
inline void reads(char *s) {
char ch = gc();
while (isspace(ch)) ch = gc();
while (!isspace(ch) && ch != EOF) *(s++) = ch, ch = gc();
*s = 0;
return;
}
template<typename T, typename ...Arg>
inline void read(T &x, Arg &... y) {
read(x);
read(y...);
}
#define O(x) cerr << #x << " : " << x << '\n'
const double Pi = acos(-1);
const int MAXN = 3e3 + 10, MOD = 998244353, inv2 = (MOD + 1) / 2, I32_INF = 0x3f3f3f3f;
const long long I64_INF = 0x3f3f3f3f3f3f3f3f;
auto Ksm = [] (int x, int y) -> int {
if (y < 0) {
y %= MOD - 1;
y += MOD - 1;
}
int ret = 1;
for (; y; y /= 2, x = (long long) x * x % MOD) if (y & 1) ret = (long long) ret * x % MOD;
return ret;
};
auto Mod = [] (int x) -> int {
if (x >= MOD) return x - MOD;
else if (x < 0) return x + MOD;
else return x;
};
template<const int N_num, const int M_num>
struct Graph {
int H[N_num];
struct Edge {int to, lac, w;} e[M_num];
inline void add_edge(int x, int y, int w) {e[*H] = {y, H[x], w};H[x] = (*H)++;}
inline void init() {memset(H, -1, sizeof H);*H = 0;}
};
#define go(x, y) for (int i = x.H[y], v; (v = x.e[i].to) && ~i; i = x.e[i].lac)
inline int ls(int k) {return k << 1;}
inline int rs(int k) {return k << 1 | 1;}
using ull = unsigned long long;
int N, M, C, sz[MAXN], A[MAXN];
vector<int> st[MAXN];
Graph<MAXN, MAXN * 2> tr;
ll f[MAXN][MAXN], g[MAXN][MAXN], dep[MAXN];
void dfs(int u, int fa, ll fval) {
// O(u);
sz[u] = A[u];
go(tr, u) if (v != fa) {
dep[v] = dep[u] + tr.e[i].w;
dfs(v, u, tr.e[i].w);
sz[u] += sz[v];
}
static ll tmpg[MAXN], tmpf[MAXN];
for (int i = 0; i <= sz[u]; ++i) tmpf[i] = I64_INF;
*f[u] = 0;
int nwsz = 0;
go(tr, u) if (v != fa) {
for (int j = 0; j <= nwsz; ++j) for (int k = 0; k <= sz[v]; ++k) chkmin(tmpf[j + k], f[u][j] + f[v][k]);
for (auto &x: st[v]) g[u][x] = I64_INF;
for (int j = 0; j <= nwsz; ++j) for (auto &x: st[v]) chkmin(g[u][x], g[v][x] + f[u][j] + j * (dep[x] - dep[u]));
for (auto &x: st[u]) tmpg[x] = I64_INF;
for (int j = 0; j <= sz[v]; ++j) for (auto &x: st[u]) chkmin(tmpg[x], g[u][x] + f[v][j] + j * (dep[x] - dep[u]));
for (auto &x: st[u]) g[u][x] = tmpg[x];
for (auto &x: st[v]) st[u].push_back(x);
nwsz += sz[v];
for (int j = 0; j <= nwsz; ++j) f[u][j] = tmpf[j], tmpf[j] = I64_INF;
}
for (int j = nwsz + A[u]; j >= A[u]; --j) f[u][j] = f[u][j - A[u]];
for (int j = A[u] - 1; j >= 0; --j) f[u][j] = I64_INF;
st[u].push_back(u);
g[u][u] = I64_INF;
for (int j = 0; j <= sz[u]; ++j) chkmin(g[u][u], f[u][j] + C);
for (auto &x: st[u]) chkmin(f[u][0], g[u][x] += A[u] * (dep[x] - dep[u]));
for (int j = 0; j <= sz[u]; ++j) f[u][j] += j * fval;
}
int main() {
freopen("post.in", "r", stdin);
// std::ios::sync_with_stdio(0);
// cout << std::fixed << std::setprecision(8);
// cin.tie(0);
// cout.tie(0);
read(N, M, C);
qwq::init(20050112);
tr.init();
for (int i = 1, x, y, c; i < N; ++i) {
read(x, y, c);
tr.add_edge(x, y, c);
tr.add_edge(y, x, c);
}
for (int i = 1, x; i <= M; ++i) read(x), A[x]++;
dfs(1, 0, 0);
// O(f[3][0]);
printf("%lld\n", f[1][0]);
// cout << (-3 / 2);
cerr << ((double) clock() / CLOCKS_PER_SEC) << '\n';
return (0-0);
}
bigben
题意
对于这个矩阵,求他的 det。
\(N \le 10 ^ {11}\) 。
这玩意我们考虑,写一个矩阵出来
考虑下一行减去上一行,然后变成了一个上海森宝矩阵,然后上海森堡矩阵的置换环每个都是类似于 \(i\to j \to j - 1 \to j - 2 \to \cdots \to i + 1 \to i\) 的,然后我们做 dp 枚举置换环算 \(\det\),令 \(A = \frac{C}{1- C}\),\(f_{i} = f_{i - 1} +v \sum_{d\vert i \and d \not = i} \left(f_d -f_{d - 1}\right)\) 这个东西,然后差分,之后杜教筛即可
然后直接杜教筛即可,我们需要注意的是,要对于 \(g_1\) 这个东西特判,因为 \(g_1 = \frac{1}{1 - C}\)。
// Siriqwq
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::copy;
using std::reverse;
using std::sort;
using std::get;
using std::unique;
using std::swap;
using std::array;
using std::cerr;
using std::function;
using std::map;
using std::set;
using std::pair;
using std::mt19937;
using std::make_pair;
using std::tuple;
using std::make_tuple;
using std::uniform_int_distribution;
using ll = long long;
namespace qwq {
mt19937 eng;
void init(int Seed) {return eng.seed(Seed);}
int rnd(int l = 1, int r = 1000000000) {return uniform_int_distribution<int> (l, r)(eng);}
}
template<typename T>
inline void chkmin(T &x, T y) {if (x > y) x = y;}
template<typename T>
inline void chkmax(T &x, T y) {if (x < y) x = y;}
template<typename T>
inline T min(const T &x, const T &y) {return x < y ? x : y;}
template<typename T>
inline T max(const T &x, const T &y) {return x > y ? x : y;}
char buf[100000], *bufs, *buft;
#define gc() ((bufs == buft && (buft = (bufs = buf) + fread(buf, 1, 100000, stdin))), bufs == buft ? -1 : *bufs++)
template<typename T>
inline void read(T &x) {
x = 0;
bool f = 0;
char ch = gc();
while (!isdigit(ch)) f = ch == '-', ch = gc();
while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
if (f) x = -x;
}
inline void reads(char *s) {
char ch = gc();
while (isspace(ch)) ch = gc();
while (!isspace(ch) && ch != EOF) *(s++) = ch, ch = gc();
*s = 0;
return;
}
template<typename T, typename ...Arg>
inline void read(T &x, Arg &... y) {
read(x);
read(y...);
}
#define O(x) cerr << #x << " : " << x << '\n'
const double Pi = acos(-1);
const int MAXN = 262144, MOD = 998244353, inv2 = (MOD + 1) / 2, I32_INF = 0x3f3f3f3f;
const long long I64_INF = 0x3f3f3f3f3f3f3f3f;
auto Ksm = [] (int x, int y) -> int {
if (y < 0) {
y %= MOD - 1;
y += MOD - 1;
}
int ret = 1;
for (; y; y /= 2, x = (long long) x * x % MOD) if (y & 1) ret = (long long) ret * x % MOD;
return ret;
};
auto Mod = [] (int x) -> int {
if (x >= MOD) return x - MOD;
else if (x < 0) return x + MOD;
else return x;
};
template<const int N_num, const int M_num>
struct Graph {
int H[N_num];
struct Edge {int to, lac, w;} e[M_num];
inline void add_edge(int x, int y, int w) {e[*H] = {y, H[x], w};H[x] = (*H)++;}
inline void init() {memset(H, -1, sizeof H);*H = 0;}
};
#define go(x, y) for (int i = x.H[y], v; (v = x.e[i].to) && ~i; i = x.e[i].lac)
inline int ls(int k) {return k << 1;}
inline int rs(int k) {return k << 1 | 1;}
using ull = unsigned long long;
const int MAXL = 3e7 + 10;
ll N, C, A;
int F[MAXL], G[MAXL], pri[MAXL], w[MAXL], mnp[MAXL], vf[MAXN];
bool vis[MAXL];
int SF(ll x) {
if (x < MAXL) return F[x];
int id = N / x;
if (vf[id]) return vf[id];
int ret = 0;
for (ll l = 2, r; l <= x; l = r + 1) {
r = x / (x / l);
ret = (ret + (r - l + 1) % MOD * SF(x / l)) % MOD;
}
return vf[id] = ((ll) ret * A + G[1]) % MOD;
}
int main() {
freopen("bigben.in", "r", stdin);
freopen("bigben.out", "w", stdout);
qwq::init(20050112);
read(N, C);
if (C == 1) {
printf("%d\n", (N <= 2));
return 0;
}
A = (ll) C * Ksm(Mod(1 - C), MOD - 2) % MOD;
G[1] = Ksm(Mod(1 - C), MOD - 2);
for (int i = 2; i < MAXL; ++i) {
if (!vis[i]) pri[++*pri] = i, mnp[i] = i, w[i] = 1;
for (int j = 1; j <= *pri && pri[j] * i < MAXL; ++j) {
if (i % pri[j]) w[i * pri[j]] = w[i] + 1, mnp[i * pri[j]] = mnp[i] * pri[j], vis[i * pri[j]] = 1;
else {
vis[i * pri[j]] = 1;
w[i * pri[j]] = w[i];
mnp[i * pri[j]] = mnp[i];
break;
}
}
}
const int wp[] = {0, 2, 6, 30, 210, 2310, 30030, 510510, 9699690};
mnp[1] = 1;
for (int i = 2; i < MAXL; ++i) {
mnp[i] = mnp[i / mnp[i]] * wp[w[i]];
if (mnp[i] != i) {
G[i] = G[mnp[i]];
continue;
}
G[i] = G[1];
for (int j = 2; j * j <= i; ++j) if (i % j == 0) {
G[i] = Mod(G[i] + G[j]);
if (j * j != i) G[i] = Mod(G[i] + G[i / j]);
}
G[i] = (long long) G[i] * A % MOD;
}
for (int i = 1; i < MAXL; ++i) F[i] = Mod(G[i] + F[i - 1]);
int ANS = SF(N);
ANS = (ll) Ksm(Mod(1 - C), N % (MOD - 1)) * ANS % MOD;
printf("%d\n", ANS);
// cout << (-3 / 2);
return (0-0);
}
run
题意
给你一段程序
void sol(int l, int r) {
if (l == r) return w(1);
int mid = (l + r) / 2;
return sol(l, mid) + sol(mid + 1, r) + w(r - l + 1);
}
其中 \(w(i) = \min\left(\left(p + 1\right)2 ^ p \vert\right)\),然后给你一个 \(01\) 串,有四种操作
- 区间覆盖(0/1)
- 区间反转(0变成1,1变成0)
- 区间查询,即对于 \([l,r]\) 区间的串,转成数字为 \(N\),查询
sol(N)
的数值,对于 \(998244353\) 取模。
\(N, M\le 10 ^ 5\)
题解
我们发现,对于 \(p\),所有 \(p = \left\lceil \log_2(x)\right\rceil\) 的 \(x\),满足 \(w(x)\) 是相等的,
考虑每个 \(x\) 的增量,对于一个 \(1\) 的最高位 \(l\),若次高位是 \(m\),那么我们对于 \(sol(x)\) 和 \(sol(x + 1)\) 只差一个 \(w(2 ^ {l - m})\) 和 \(w(1)\)。然后考虑我们可以找到目标串的第一个 \(1\),然后第二个 \(1\) 分别的位置 \(k, m\),先算前面第一个 \(1\) 的增量 \(\frac{(p + 1)(p + 2) 2 ^ p}{2}\),然后算第二个 \(1\) 的增量 \(2 ^ m - 1 + \frac{m 2 ^ k (2k - m + 3)}{2} + 2 ^ {k + 1}(k + 2)\),然后之后的贡献就是后面的权值乘上对应的 \(w\) 即可
// Siriqwq
#include <bits/stdc++.h>
using std::cin;
using std::cout;
using std::vector;
using std::copy;
using std::reverse;
using std::sort;
using std::get;
using std::unique;
using std::swap;
using std::array;
using std::cerr;
using std::function;
using std::map;
using std::set;
using std::pair;
using std::mt19937;
using std::make_pair;
using std::tuple;
using std::make_tuple;
using std::uniform_int_distribution;
using ll = long long;
namespace qwq {
mt19937 eng;
void init(int Seed) {return eng.seed(Seed);}
int rnd(int l = 1, int r = 1000000000) {return uniform_int_distribution<int> (l, r)(eng);}
}
template<typename T>
inline void chkmin(T &x, T y) {if (x > y) x = y;}
template<typename T>
inline void chkmax(T &x, T y) {if (x < y) x = y;}
template<typename T>
inline T min(const T &x, const T &y) {return x < y ? x : y;}
template<typename T>
inline T max(const T &x, const T &y) {return x > y ? x : y;}
char buf[100000], *bufs, *buft;
#define gc() ((bufs == buft && (buft = (bufs = buf) + fread(buf, 1, 100000, stdin))), bufs == buft ? -1 : *bufs++)
template<typename T>
inline void read(T &x) {
x = 0;
bool f = 0;
char ch = gc();
while (!isdigit(ch)) f = ch == '-', ch = gc();
while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
if (f) x = -x;
}
inline void reads(char *s) {
char ch = gc();
while (isspace(ch)) ch = gc();
while (!isspace(ch) && ch != EOF) *(s++) = ch, ch = gc();
*s = 0;
return;
}
template<typename T, typename ...Arg>
inline void read(T &x, Arg &... y) {
read(x);
read(y...);
}
#define O(x) cerr << #x << " : " << x << '\n'
const double Pi = acos(-1);
const int MAXN = 262144, MOD = 998244353, inv2 = (MOD + 1) / 2, I32_INF = 0x3f3f3f3f;
const long long I64_INF = 0x3f3f3f3f3f3f3f3f;
auto Ksm = [] (int x, int y) -> int {
if (y < 0) {
y %= MOD - 1;
y += MOD - 1;
}
int ret = 1;
for (; y; y /= 2, x = (long long) x * x % MOD) if (y & 1) ret = (long long) ret * x % MOD;
return ret;
};
auto Mod = [] (int x) -> int {
if (x >= MOD) return x - MOD;
else if (x < 0) return x + MOD;
else return x;
};
template<const int N_num, const int M_num>
struct Graph {
int H[N_num];
struct Edge {int to, lac;} e[M_num];
inline void add_edge(int x, int y) {e[*H] = {y, H[x]};H[x] = (*H)++;}
inline void init() {memset(H, -1, sizeof H);*H = 0;}
};
#define go(x, y) for (int i = x.H[y], v; (v = x.e[i].to) && ~i; i = x.e[i].lac)
inline int ls(int k) {return k << 1;}
inline int rs(int k) {return k << 1 | 1;}
using ull = unsigned long long;
int N, M, p[MAXN], ip[MAXN], A[MAXN];
char s[MAXN];
int rev[MAXN * 4], cnt[MAXN * 4], val[MAXN * 4], tag[MAXN * 4];
inline int gt(int l, int r) {return Mod(p[r + 1] - p[l]);}
inline void up(int k) {
cnt[k] = cnt[ls(k)] + cnt[rs(k)];
val[k] = Mod(val[ls(k)] + val[rs(k)]);
}
inline void puttag(int k, int rtg, int atg, int l, int r) {
if (~atg) {
tag[k] = atg;
rev[k] = 0;
val[k] = atg ? gt(l, r) : 0;
cnt[k] = atg ? (r - l + 1) : 0;
}
if (rtg) {
val[k] = Mod(gt(l, r) - val[k]);
cnt[k] = r - l + 1 - cnt[k];
rev[k] ^= 1;
}
}
inline void down(int k, int l, int r) {
int mid = (l + r) / 2;
puttag(ls(k), rev[k], tag[k], l, mid);
puttag(rs(k), rev[k], tag[k], mid + 1, r);
tag[k] = -1;
rev[k] = 0;
}
void build(int k, int l, int r) {
tag[k] = -1;
if (l == r) {
val[k] = A[l] * p[l];
cnt[k] = A[l];
return;
}
int mid = (l + r) / 2;
build(ls(k), l, mid);
build(rs(k), mid + 1, r);
up(k);
}
void mfy_rev(int k, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return puttag(k, 1, -1, l, r);
int mid = (l + r) / 2;
down(k, l, r);
if (ql <= mid) mfy_rev(ls(k), l, mid, ql, qr);
if (mid < qr) mfy_rev(rs(k), mid + 1, r, ql, qr);
up(k);
}
void mfy_agn(int k, int l, int r, int ql, int qr, int tg) {
if (ql <= l && r <= qr) return puttag(k, 0, tg, l, r);
int mid = (l + r) / 2;
down(k, l, r);
if (ql <= mid) mfy_agn(ls(k), l, mid, ql, qr, tg);
if (mid < qr) mfy_agn(rs(k), mid + 1, r, ql, qr, tg);
up(k);
}
int findr(int ql, int qr) {
if (ql > qr) return -1;
function<int(int, int, int)> dfs = [&] (int nw, int l, int r) -> int {
if (ql <= l && r <= qr) {
if (!cnt[nw]) return -1;
if (l == r) return l;
else {
down(nw, l, r);
int mid = (l + r) / 2;
if (cnt[rs(nw)]) return dfs(rs(nw), mid + 1, r);
else return dfs(ls(nw), l, mid);
}
}
down(nw, l, r);
int mid = (l + r) / 2;
if (mid < qr) {
int ret = dfs(rs(nw), mid + 1, r);
if (ret != -1) return ret;
}
if (ql <= mid) {
int ret = dfs(ls(nw), l, mid);
if (ret != -1) return ret;
}
return -1;
};
return dfs(1, 1, N);
}
int qry(int k, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return val[k];
int mid = (l + r) / 2, ret = 0;
down(k, l, r);
if (ql <= mid) ret = qry(ls(k), l, mid, ql, qr);
if (mid < qr) ret = Mod(ret + qry(rs(k), mid + 1, r, ql, qr));
return ret;
}
inline int getf(int x) {return ((x + 1LL) * p[x] + 1) % MOD;}
int ans(int l, int r) {
int k = findr(l, r);
// 没有 1 存在
// O(k);
if (k == -1) return 0;
int m = findr(l, k - 1);
if (m == -1) {
// 2 的 幂次
k -= l;
return (k + 1LL) * (k + 2LL) / 2 % MOD * p[k] % MOD;
}
m -= l;
k -= l;
// 最高位贡献
int ANS = (k + 1LL) * (k + 2LL) / 2 % MOD * p[k] % MOD;
// 加到第一个
ANS = Mod(ANS + getf(k + 1));
// 后面除了最高位和次高位的贡献
ANS = (ANS + getf(k - m) * ((ll) qry(1, 1, N, l, r) * ip[l] % MOD - p[k] - p[m] + 2LL * MOD)) % MOD;
// 还有就是怎么加到次高位
ANS = (ANS + p[m] - 1 + p[k] * (k * 2LL - m + 3) % MOD * m % MOD * inv2) % MOD;
return ANS;
}
int main() {
freopen("run.in", "r", stdin);
freopen("run.out", "w", stdout);
// std::ios::sync_with_stdio(0);
// cout << std::fixed << std::setprecision(8);
// cin.tie(0);
// cout.tie(0);
qwq::init(20050112);
read(N, M);
reads(s + 1);
for (int i = 1; i <= N; ++i) A[i] = s[i] - '0';
p[0] = ip[0] = 1;
for (int i = 1; i < MAXN; ++i) p[i] = p[i - 1] * 2 % MOD, ip[i] = (ll) ip[i - 1] * inv2 % MOD;
build(1, 1, N);
for (int i = 1, opt, l, r; i <= M; ++i) {
read(opt, l, r);
if (opt == 1) mfy_rev(1, 1, N, l, r);
else if (opt == 2) mfy_agn(1, 1, N, l, r, 0);
else if (opt == 3) mfy_agn(1, 1, N, l, r, 1);
else printf("%d\n", ans(l, r));
}
// cout << (-3 / 2);
cerr << ((double) clock() / CLOCKS_PER_SEC) << '\n';
return (0-0);
}