题解:「USACO 2020.2 Platinum」Help Yourself
首先考虑 \(k = 1\) 的情况。
发现每条线段对前后的答案都有影响,所以按左端点排序,从左到右处理。
记 \(f_i\) 表示以 \(i\) 为结尾的线段集合的答案,最终答案即为 \(\sum_{i=1}^{2n} f_i\) 。
对于每条加进来的线段 \(\begin{bmatrix}l,r\end{bmatrix}\) 对于不同 \(f_i\) 的贡献进行分类讨论。
- 对于所有 \(i < l\) ,此时加入这条线段后,对 \(f_r\) 的贡献即为 \(f_i + 1\) ,可以表达为 \(f_r \gets f_r + \sum_{i=1}^{l-1} f_i+1\) 。
- 对于所有 \(i\in[l,r]\) ,加入线段后,复杂度不变,所以对 \(f_r\) 的贡献即为 \(f_i\) ,可以表达为 \(f_r \gets f_r + \sum_{i=l}^{r} f_i\)。
- 对于所有 \(i > r\) ,因为按照左端点排序,所以加入线段后,复杂度不变,所以 \(f_i\) 对 \(f_i\) 的贡献即为 \(f_i\) ,可以表达为 \(f_i \gets f_i \times 2\)
可以直接前缀和或者线段树维护。
考虑 \(k > 1\)
发现棘手的地方在于维护第一种情况出现的 \(\sum_{i=1}^{l-1} (f_i+1)^k\) 。
这里有两种解决方案。
方案一:
根据二项式定理 \((f_i+1)^k = \sum_{j=0}^{k} {k \choose j} f_i^j\) 。
因为 \(k\leq 10\) ,直接用线段树维护每个指数所对应的值即可。
方案二:
大力拆式子。
设 \(g_s\) 表示 \(k=1\) 时线段集合 \(s\) 的答案,发现最终答案可以表达为 \(\sum_s g_s^k\) 。
直接套路次幂拆第二类斯特林数,得到:
换一下求和顺序,得:
设 \(S_i\) 表示以第 \(i\) 个节点结束的线段集合的集合,维护对象改为对于每一个 \(j\) ,求:
再看一下上面的讨论,发现后两种针对总体贡献,直接翻倍相加即可。
问题变为如何处理 \(\displaystyle{{g_s\choose j} \rightarrow {g_s+1 \choose j}}\) 。
根据加法恒等式发现有转移:
可以用线段树维护每个 \(f_{i,j}\) ,发现转移后面的东西已经都维护好了,直接转移即可,具体表达 \(f_{i,j} \gets f_{i,j} + f_{i,j-1}\) 。
时间复杂度 \(\mathcal{O}(nk\log n + nk)\)
Code(C++):
#include <bits/stdc++.h>
#define forn(i,s,t) for(register int i=(s);i<=(t);++i)
using namespace std;
typedef long long LL;
const int N = 1e5 + 3, M = 4e5 + 1e2, Mod = 1e9 + 7;
template<typename T>inline void redn(T &ret) {
static char ch;
ret = 0, ch = getchar();
while (!isdigit(ch))
ch = getchar();
while (isdigit(ch))
ret = (ret << 1) + (ret << 3) + ch - 48, ch = getchar();
}
int k;
LL wgt[11], trans[11];
class SegTree {
private:
int L[M], R[M], sl;
LL val[M][11], tag[M];
inline void push_up(int p) {
forn(i, 0, k) val[p][i] = val[L[p]][i] + val[R[p]][i], val[p][i] %= Mod;
}
inline void Opt(int p, LL value) {
forn(i, 0, k) val[p][i] = val[p][i] * value % Mod;
tag[p] = tag[p] * value % Mod;
}
inline void push_down(int p) {
Opt(L[p], tag[p]), Opt(R[p], tag[p]);
tag[p] = 1ll;
}
public:
int rt;
void Bld(int &p, int l, int r) {
p = ++sl, tag[p] = 1;
if (l == r)
return ;
int mid = l + r >> 1;
Bld(L[p], l, mid), Bld(R[p], mid + 1, r);
push_up(p);
}
void Qry(int p, int l, int r, int nl, int nr) {
if (l == nl && nr == r) {
forn(i, 0, k) wgt[i] = wgt[i] + val[p][i], wgt[i] %= Mod;
return ;
}
(tag[p] ^ 1) &&(push_down(p), 0);
int mid = nl + nr >> 1;
if (r <= mid)
Qry(L[p], l, r, nl, mid);
else if (l > mid)
Qry(R[p], l, r, mid + 1, nr);
else
Qry(L[p], l, mid, nl, mid), Qry(R[p], mid + 1, r, mid + 1, nr);
}
void Upd(int p, int l, int r, int pos) {
if (l == r) {
forn(i, 0, k) val[p][i] = val[p][i] + trans[i], val[p][i] %= Mod;
return ;
}
(tag[p] ^ 1) &&(push_down(p), 0);
int mid = l + r >> 1;
if (pos <= mid)
Upd(L[p], l, mid, pos);
else
Upd(R[p], mid + 1, r, pos);
push_up(p);
}
void Mul(int p, int l, int r, int nl, int nr) {
if (l == nl && nr == r)
return Opt(p, 2ll);
(tag[p] ^ 1) &&(push_down(p), 0);
int mid = nl + nr >> 1;
if (r <= mid)
Mul(L[p], l, r, nl, mid);
else if (l > mid)
Mul(R[p], l, r, mid + 1, nr);
else
Mul(L[p], l, mid, nl, mid), Mul(R[p], mid + 1, r, mid + 1, nr);
push_up(p);
}
} T;
int n, m, l[N], r[N], id[N];
LL S[11][11], fac[11], Ans;
inline bool cmp(int A, int B) {
return l[A] < l[B];
}
int main() {
redn(n), redn(k);
m = (n << 1) + 1;
T.Bld(T.rt, 0, m);
forn(i, 1, n) redn(l[i]), redn(r[i]), id[i] = i;
sort(id + 1, id + n + 1, cmp);
trans[0] = 1;
T.Upd(T.rt, 0, m, 0);
forn(i, 1, n) {
forn(j, 0, k) wgt[j] = 0;
T.Qry(T.rt, 0, l[id[i]] - 1, 0, m);
trans[0] = wgt[0];
forn(j, 1, k) trans[j] = wgt[j] + wgt[j - 1], trans[j] %= Mod;
forn(j, 0, k) wgt[j] = 0;
T.Qry(T.rt, l[id[i]], r[id[i]], 0, m);
forn(j, 0, k) trans[j] = trans[j] + wgt[j], trans[j] %= Mod;
T.Upd(T.rt, 0, m, r[id[i]]);
T.Mul(T.rt, r[id[i]] + 1, m, 0, m);
forn(j, 0, k) wgt[j] = 0ll;
T.Qry(T.rt, 0, m, 0, m);
}
forn(i, 0, k) wgt[i] = 0;
T.Qry(T.rt, 0, m, 0, m);
S[0][0] = 1;
forn(i, 1, k) forn(j, 1, k) S[i][j] = (S[i - 1][j - 1] + 1ll * j * S[i - 1][j] % Mod) % Mod;
fac[0] = 1ll;
forn(i, 1, k) fac[i] = 1ll * i * fac[i - 1] % Mod;
forn(i, 0, k) Ans += S[k][i] * fac[i] % Mod * wgt[i] % Mod, Ans %= Mod;
printf("%lld\n", Ans);
return 0;
}