闲话 23.3.1
闲话
所以 cd 为啥突然学 gf
然后整出来一大堆奇怪的(初学者可能会有的)问题
建议来问我(
我还能乐呵乐呵(
EI:那你以后要知道这不奇怪
EI:小学生在初学负数时也会有疑惑
今日推歌:REWRITER - 八王子P feat. GUMI
杂题
我担心今天只有这一道了(
给定一个长为 \(n\) 的序列 \(a\),记 \(a\) 的下标落在区间 \([l, r]\) 内的元素组成的序列为 \(a[l:r]\)。
\(q\) 次询问,每次给定 \(l, r\),求 \(a[l:r]\) 的所有连续子序列最小值的和。
\(n, q\le 10^5, |a_i|\le 10^9\)。
这题让我充分意识到我不会莫队变式了。
我们发现,题目要求的信息是容易由 \([l, r]\) 得到 \([l, r + 1]\) 的。这里只说右端点递增的情况,另三种移动端点的策略类似。
考虑当右端点递增时,我们只需要考虑 \(\forall k\in [l, r + 1],\ \min\{a[k:r + 1]\}\) 的贡献。也就是说,贡献区间的右端点是固定的。
不难想到,这贡献随 \(k\) 递减而减小,并且若 \(p = \text{arg min}_{i = l}^r a_i\),则 \(k\in [l, p]\) 时贡献都为 \(a_p\)。则我们求出 \(p\) 后 \([l, p]\) 段的贡献就是 \((p - l + 1) \times a_p\),我们之后只需要观察递减的 \(k\in [p + 1, r + 1]\) 段。
这段的贡献是好求的。可以知道的是,若对于一个区间 \([l_0, r_0]\subseteq [p + 1, r + 1]\),若 \(r_0 = \text{arg min}_{i = l_0}^{r_0} a_i\),则这一段内某个位置作为左端点的贡献对任意的 \(r + 1\) 都是相同的。也就是说,我们预处理一个 \(\text{lm}[i]\) 表示 \(i\) 左侧第一个小于 \(a_i\) 的值,则当计算 \(p\le \text{lm}[i] < i\le r + 1\) 的答案时,这一段可以对答案贡献 \((i - \text{lm}[i]) \times a_i\)。预处理这个的前缀和即可。
因此我们就将一段区间拆解为了两段贡献,他们都是可以在 \(O(1)\) 得到的。
因此作莫队,可以得到 \(O(n\sqrt n)\) 的做法。
之后再补在线做法吧(
code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i,s,t) for (register int i = (s), i##_ = (t) + 1; i < i##_; ++ i)
#define pre(i,s,t) for (register int i = (s), i##_ = (t) - 1; i > i##_; -- i)
const int N = 2e5 + 10;
signed main() {
static int n, q, a[N], st[21][N], lgv[N];
cin >> n >> q;
rep(i,1,n) cin >> a[i], st[0][i] = i;
rep(i,2,n) lgv[i] = lgv[i >> 1] + 1;
rep(i,1,lgv[n]) rep(j,1,n - (1 << i) + 1) {
int u = st[i - 1][j], v = st[i - 1][j + (1 << i - 1)];
st[i][j] = a[u] < a[v] ? u : v;
}
auto getmin = [&](int l, int r) {
int d = lgv[r - l + 1];
l = st[d][l], r = st[d][r - (1 << d) + 1];
return a[l] < a[r] ? l : r;
};
static int lm[N], rm[N], stk[N], top;
static ll lsum[N], rsum[N];
a[0] = - 1.5e9;
stk[top = 1] = 0;
rep(i,1,n) {
while (top and a[stk[top]] >= a[i]) -- top;
lm[i] = stk[top]; stk[++ top] = i;
}
a[0] = 0;
a[n + 1] = - 1.5e9;
stk[top = 1] = n + 1;
pre(i,n,1) {
while (top and a[stk[top]] >= a[i]) -- top;
rm[i] = stk[top]; stk[++ top] = i;
}
rep(i,1,n) lsum[i] = lsum[lm[i]] + 1ll * (i - lm[i]) * a[i];
pre(i,n,1) rsum[i] = rsum[rm[i]] + 1ll * (rm[i] - i) * a[i];
static int sqv = sqrt(n) + 5, bel[N];
static ll ans[N], now = 0;
static struct queries {
int l, r, id;
bool operator < (const queries& b) const {
if (bel[l] == bel[b.l]) {
if (bel[l] & 1) return r < b.r;
else return r > b.r;
} return l < b.l;
}
} qy[N];
auto movel = [&](int l, int r) {
int pos = getmin(l, r);
return rsum[l] - rsum[pos] + 1ll * (r - pos + 1) * a[pos];
};
auto mover = [&](int l, int r) {
int pos = getmin(l, r);
return lsum[r] - lsum[pos] + 1ll * (pos - l + 1) * a[pos];
};
rep(i,1,q) cin >> qy[i].l >> qy[i].r, qy[i].id = i;
rep(i,1,n) bel[i] = (i - 1) / sqv + 1;
sort(qy + 1, qy + 1 + q);
for (int i = 1, l = 1, r = 0; i <= q; ++ i) {
while (qy[i].l < l) now += movel(-- l, r);
while (r < qy[i].r) now += mover(l, ++ r);
while (l < qy[i].l) now -= movel(l ++, r);
while (qy[i].r < r) now -= mover(l, r --);
ans[qy[i].id] = now;
}
rep(i,1,q) cout << ans[i] << '\n';
}
一个非负整数序列 \(S\) 是好的,当且仅当 \(S\) 存在一个非空子序列 \(T\),满足 \(T\) 中所有元素的异或和为 \(1\)。
有一个初始为空的序列 \(A\),以及 \(2^m\) 张写着数字的卡片;卡片上的数字取遍 \([0, 2^m)\) 中的整数。你可以自由选择一张卡片,将这张卡片上的数字放在 \(A\) 序列的末尾,并删除这张卡片,以后不能再选择它。你会一直进行这个操作,当 \(A\) 成为好的序列后停止。
给定 \(n, m\),求停止操作时长度为 \(n\) 的不同 \(A\) 序列数。答案对 \(998244353\) 取模。
\(1\le n\le 2\times 10^5, \ 1\le m \le 10^7,\ n\le 2^m\)。
想装b 去选金牌题做 然后发现哪个都不可做就跑路了 找了个这个题
增加水题提交数(
前置知识。
题目中的生成方式等价于钦定序列 \(S\) 中数字互异。
设 \(A_n\) 是长度为 \(n\) 的好序列数量(数字不必两两不同),则答案即为 \(A_n - A_{n - 1} \times (2^m - n + 1)\)。这转化使我们可以简单容斥,用长度为 \(n\) 的序列总数减去数字互异的坏序列数就是答案。下面只需要计算数字互异的坏序列数即可。
设 \(f(n)\) 为数字互异的坏序列数,\(g(n)\) 为坏序列数。由于数字顺序对性质无影响,我们可以取一个数字互异的坏序列,将其中第 \(i\) 个元素扩增 \(k_i\ge 1\) 倍得到一个一般的坏序列。可以将每个数字看做一个盒子,第 \(i\) 个盒子中放 \(k_i\) 个球。这的组合意义自然导出了如下公式:
斯特林反演得到
我们已经充分了解了如何 \(O(n\log n)\) 求得一行斯特林数,下面只需要求得每个 \(g(k)\) 即可。这问题即为 CF1603F 当 \(x > 0\) 时的情况。我们已经知道了
一次卷积即可。
总时间复杂度为 \(O(n\log n + m)\),需要预处理 \(\text{q-}\)阶乘和它的逆元。
给定 \(n, m\),保证 \(n\le m\le 2n\)。设 \(a\) 枚举长度为 \(n\) 且满足 \(\sum_{i = 1}^n a_i = m\) 的所有序列 \(a\),求
\[\sum_{a} \prod_{i = 1}^n \min(i, a_i) \]\(1\le n\le 10^{12}\)。
看到经典的枚举序列的形式,我们不妨考虑枚举第 \(i\) 个元素取值为 \(a_i\) 时的贡献,并写成 gf 形式,最后乘起来提取 \(x^m\) 项系数即可。
考虑 \(F_k(x) = x + 2x^2 + 3x^3 + \cdots + kx^k + kx^{k + 1} + kx^{k + 2} + \cdots\),我们知道这就是第 \(i\) 个元素的贡献,而答案就是 \([x^m] \prod_k F_k(x)\)。我们首先要得到 \(F_k\) 的封闭形式。
我反正是暴力推导的。
题解给出了一种更妙的做法:注意到 \(F_k(x) (1 - x) = x + x^2 + x^3 + \cdots + x^k\),进而 \(F_k(x) (1 - x)^2 = x - x^{k + 1}\),我们能得到 \(F_k(x) = \dfrac{x(1 - x^k)}{(1 - x)^2}\)。
那答案就是
注意到 \(0\le m - n\le n\),因此在提取系数的过程中 \(\prod_{k = 1}^n (1 - x^{k})\) 等价于 \(\prod_{k = 1}^{\infty} (1 - x^{k})\),而后者就是欧拉函数的生成函数。五边形数定理是广为人知的,它指出了
因此在整个过程中,\(\prod_{k = 1}^n (1 - x^{k})\) 只有 \(O(\sqrt n)\) 个位置有值,我们将他记作 \(\sum_{i = 0}^k f_i x^{a_i}\);\(k = O(\sqrt n)\),\(f_i\neq 0\)。
这样我们就可以自然地展开原式了。
由于本题的模数较小,我们可以通过 Lucas 定理在 \(O(\sqrt n\log n + \text{mod})\) 的复杂度内计算上式的值。
以下是博客签名,与正文无关。
请按如下方式引用此页:
本文作者 joke3579,原文链接:https://www.cnblogs.com/joke3579/p/chitchat230301.html。
遵循 CC BY-NC-SA 4.0 协议。
请读者尽量不要在评论区发布与博客内文完全无关的评论,视情况可能删除。