淮南市网站建设_网站建设公司_会员系统_seo优化
2026/1/21 10:24:42 网站建设 项目流程

现在网上找不到题解,QOJ上的论文看不了了,来贡献一篇。

题目链接

\(U(x, s)\) 表示从 \(x\) 一个单独的数开始,进行 \(s\) 次操作后得到的序列。

举个例子,若 \(p = \{1, 4, 3, 2\}\),那么 \(U(4, 0) = \{4\}, U(4, 1) = \{1,4,3,2\}, U(4, 2) = \{1,1,4,3,2,1,3,2,1,2\}\)

将询问的答案记为 \(f(x, k, a, s)\),表示再 \(U(x, s)\) 中前 \(a\) 个数里面数字 \(k\) 的个数。

设序列相加为连接序列,可以发现 \(U(x, s) = \sum\limits_{i = 1} ^ n [p_i\le x]U(p_i, s - 1)\)。所以我们可以把 \(f(x, k, a, s)\) 进行拆分:

\[f(x, k, a, s) = \sum\limits_{i = 1} ^ n [p_i\le x]f(p_i, k, a_i, s - 1) \]

\(U(x, s)\) 的序列长度为 \(g(x, s)\)。这样 \(a_i\) 是容易求出的,具体的,我们把所有满足 \(p_i \le x\)\(p_i\) 按照排列里的顺序拿出来,这样它们的长度依次是 \(g(p_{i_1}, s - 1), g(p_{i_2}, s - 1), \cdots , g(p_{i_m}, s - 1)\),对这个序列进行前缀和,二分出最后一个前缀和小于等于 \(a\) 的位置记为 \(st\),设 \(st\) 之前的前缀和为 \(sum\),那么就可以得出:

\[f(x, k, a, s) = f(p_{i_{st + 1}}, k, a - sum, s - 1) + \sum\limits_{u = 1} ^ {st} f(p_{i_u}, k, g(p_{i_u}, s - 1), s - 1) \]

等式右边第一项扔去 \(s - 1\) 继续计算,第二项形式比较好,考虑快速计算的方法,设 \(h(x, k, s) = f(x, k, g(x, s), s)\)

发现对于一个固定的 \(k\),对于 \(s \ge 1\)\(h\) 有递推式:

\[h(x, k, s) = \sum\limits_{i = 1} ^ {x} h(i, k, s - 1) = h(x - 1, k, s) + h(x, k, s - 1) \]

边界是 \(h(x, k, 0) = [x = k]\)。这是一个经典的格路计数的递推式,对于 \(s\ge 1\) 的情况,\(h(x, k, s)\) 可以看成从格点 \((k, 1)\) 到格点 \((x, s)\) 的路径个数,容易知道答案是 \([x\ge k]{x + s - k - 1\choose s - 1}\)。若 \(s = 0\),根据边界条件计算即可。

好了,现在思路大体有了,考虑如何实现。

首先是 \(g(x, s)\) 的计算,和 \(h\) 类似 \(g(x, s) = g(x - 1, s) + g(x, s - 1)\)

记题目里面的 \(s\)\(S\)。那么每个询问就是 \(f(n, k, a, S)\)

我们从最大的 \(s = S\) 开始处理,一直到 \(s = 0\) 结束。

首先考虑如何将 \(f(x, k, a, s)\) 拆分成我们想要的形式。将询问按照 \(x\) 从小到大排序,设 \(rk_{p_i} = i\),在处理 \(x\) 的询问前,将所有满足 \(u \le x\)\(u\)\(g(u, s - 1)\) 放到下标为 \(rk_u\) 的位置上,快速求前缀和二分可以用树状数组结合倍增实现。

我们记录 \(\tau(x, i_{st}, k, s) = \sum\limits_{u = 1} ^ {st} h(p_{i_u}, k, s) = \sum\limits_{u = 1} ^ {st} [p_{i_u}\ge k]{p_{i_u} + s - k - 1\choose s - 1}\) 作为新的查询,但是这不好处理,考虑拆分组合数,使用范德蒙德卷积(其中 \(y\) 代表 \(p_{i_u}\)):

\[{y + s - k - 1\choose s - 1} = \sum\limits_{j = 0} ^ {s - 1}{s -1 - k\choose s - 1 - j}\times {y \choose j} \]

这样求和式中的左右两项是独立的,每次查询时可以枚举 \(j\),用数据结构求出 \(\sum{p_t\choose j}\),然后可以数点了。

但是要注意这里组合数有可能上指标是负的,这也要考虑进去,计算时使用上指标反转即可:

\[{n\choose r} = (-1) ^ r {r - n - 1\choose r} \]

考虑询问 \(\tau(x, r, k, s)\) 对点的限制:\(y \ge k, y\le x, rk_y\le r\)。直接二维数点即可。

时间复杂度 \(\mathcal O(s(n + q)\log n)\)

mint inv[N], fac[N], ifac[N];
inline mint C(int n, int r) {if (r < 0 || (n >= 0 && r > n)) return mint(0);if (n < 0) {if (r & 1) return mint(Mod - 1) * C(r - n - 1, r);else return C(r - n - 1, r);}return fac[n] * ifac[n - r] * ifac[r];
}
inline void Invtable(int n) {inv[1] = mint(1);forn (i, 2, n) inv[i] = mint(Mod - Mod / i) * inv[Mod % i];fac[0] = 1, ifac[0] = 1;forn (i, 1, n) fac[i] = fac[i - 1] * mint(i), ifac[i] = ifac[i - 1] * inv[i];
}
struct BIT {ll val[N]; int R, Lg;inline void init(int lim) { forn (i, 1, R) val[i] = 0; R = lim, Lg = log2(lim); }inline void upd(int p, ll k) { while (p <= R) val[p] += k, p += p & -p; }inline ll qry(int p) { ll r = 0; while (p > 0) r += val[p], p -= p & -p; return r; }inline pair<int, ll> qs(ll t) {ll sum = 0; int st = 0;form (i, Lg, 0) if ((st | (1 << i)) <= R && sum + val[st | (1 << i)] <= t) st |= 1 << i, sum += val[st];assert(sum <= t);return make_pair(st, sum);}
} T;
struct mBIT {mint val[N]; int R;inline void init(int lim) { forn (i, 1, R) val[i] = 0; R = lim; }inline void upd(int p, mint k) { while (p <= R) val[p] += k, p += p & -p; }inline mint qry(int p) { mint r = 0; while (p > 0) r += val[p], p -= p & -p; return r; }inline mint qry(int l, int r) { return qry(r) - qry(l - 1); }
} Tm[6];
int rk[N];
struct Q1 {int id, k, a;Q1 () {}Q1 (int _i, int _k, int _a) : id(_i), k(_k), a(_a) {}
};
struct Q2 {int id, k, l;Q2 () {}Q2 (int _i, int _k, int _l) : id(_i), k(_k), l(_l) {}
};
int n, S, q, p[N]; mint ans[M]; ll g[N][6];
vector<Q1> E[N], R[N]; vector<Q2> G[N];
int vis[N];
inline void solve() {cin >> n >> S >> q;Invtable(max(n, S));forn (i, 1, n) cin >> p[i], rk[p[i]] = i;forn (i, 1, n) g[i][0] = 1;forn (s, 1, S) forn (i, 1, n) g[i][s] = min(g[i - 1][s] + g[i][s - 1], INF);forn (i, 1, q) {int k, a;cin >> k >> a;E[n].push_back(Q1(i, k, a));}form (s, S - 1, 0) {T.init(n);forn (i, 1, n) {T.upd(rk[i], g[i][s]);for (Q1 e : E[i]) {auto res = T.qs(e.a);int st = res.first;ll sum = res.second;if (st) {if (s) G[st].push_back(Q2(e.id, e.k, i));else G[i].push_back(Q2(e.id, e.k, st));}if (e.a - sum) R[p[st + 1]].push_back(Q1(e.id, e.k, e.a - sum));} }if (s == 0) {forn (i, 1, n) {vis[i] = 1;for (Q2 e : G[i]) if (vis[e.k] && rk[e.k] <= e.l) ans[e.id] += mint(1);}break ;}forn (i, 1, n) swap(E[i], R[i]), R[i].clear();rep (u, 0, s) Tm[u].init(n);forn (i, 1, n) {rep (j, 0, s) Tm[j].upd(p[i], C(p[i], j));for (Q2 e : G[i]) if (e.k <= e.l) rep (j, 0, s) ans[e.id] += C(s - 1 - e.k, s - 1 - j) * Tm[j].qry(e.k, e.l);}forn (i, 1, n) G[i].clear();}forn (i, 1, q) cout << ans[i].r << '\n';
}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询