关键字挖掘爱站网,网络规划设计师岗位职责,建设掌上银行官方网站,网站每年空间域名费用及维护费problem
luogu-P3643
solution
有个显然的暴力 dpdpdp。设 dp(i,j):dp(i,j):dp(i,j): 到了第 iii 个学校#xff0c;其参加且派出 jjj 个划艇的方案数。
枚举上一个参加的学校以及派出的划艇#xff0c;则有转移#xff1a;dp(i,j)∑ki,jjdp(k,j′)dp(i,j)\sum_…problem
luogu-P3643
solution
有个显然的暴力 dpdpdp。设 dp(i,j):dp(i,j):dp(i,j): 到了第 iii 个学校其参加且派出 jjj 个划艇的方案数。
枚举上一个参加的学校以及派出的划艇则有转移dp(i,j)∑ki,jjdp(k,j′)dp(i,j)\sum_{ki,jj} dp(k,j)dp(i,j)∑ki,jjdp(k,j′)。
可以再套个前缀和优化但是由于第二维可以达到 1e91e91e9并没有起到关键性优化。
实际上我们并不关系真的派出了多少个划艇我们只在乎之间的满足的递增关系。
所以我们可以考虑离散化成 O(2n)O(2n)O(2n) 个端点。[ai,ai1)→i[a_i,a_{i1})\rightarrow i[ai,ai1)→i。
设 f(i,j):f(i,j):f(i,j): 前 iii 所学校中第 iii 所学校参赛且派出的划艇数属于第 jjj 个区间内的方案数。
Lemma:\text{Lemma}:Lemma: 从区间 [0,L][0,L][0,L] 中取 nnn 个数要求所有非零数严格递增方案数为 (Lnn)\binom {Ln}n(nLn)。 Proof:\text{Proof}:Proof: 没有 000 的情况答案肯定是 (Ln)\binom Ln(nL)。因为如果确定了一种组合那么方案也随之确定即为这个组合的从小到大排列。所以这二者存在一一对应的关系。有 000 。观察这个序列 0 0 0 ... 0 1 2 ... L\text{0 0 0 ... 0 1 2 ... L}0 0 0 ... 0 1 2 ... L。考虑从中选 nnn 个数取某个非零数 iii 对应没取 000 的第 iii 次选 iii。 现在由于第 iii 所学校必须参赛所以计算的时候 000 的个数 −1-1−1。方案数即 (Lm−1m)\binom{Lm-1}m(mLm−1)。
其中 mmm 表示选划艇个数包含第 jjj 个区间的学校数量。
对于一个 kkk对应方案数为 (Lm−1m)∑j′jf(k,j′)\binom {Lm-1}m\sum_{jj}f(k,j)(mLm−1)∑j′jf(k,j′)。
所以 f(i,j)∑ki(Lm−1m)∑j′jf(k,j‘)f(i,j)\sum_{ki}\binom{Lm-1}{m}\sum_{jj}f(k,j‘)f(i,j)∑ki(mLm−1)∑j′jf(k,j‘)。
此时再加前缀和优化sum(k,j)∑j′jf(k,j′)sum(k,j)\sum_{jj}f(k,j)sum(k,j)∑j′jf(k,j′)。
则 f(i,j)∑ki(Lmk−1mk)sum(k,j)f(i,j)\sum_{ki}\binom{Lm_k-1}{m_k}sum(k,j)f(i,j)∑ki(mkLmk−1)sum(k,j)。
时间复杂度 O(n3)O(n^3)O(n3)。
code
#include bits/stdc.h
using namespace std;
#define maxn 1005
#define int long long
#define mod 1000000007
int n;
int a[maxn], b[maxn], c[maxn], x[maxn], inv[maxn], sum[maxn];signed main() {scanf( %lld, n );for( int i 1;i n;i ) {scanf( %lld %lld, a[i], b[i] );x[i] a[i], x[i n] b[i] 1;}sort( x 1, x (n 1 | 1) );int m unique( x 1, x (n 1 | 1) ) - x - 1;for( int i 1;i n;i ) {a[i] lower_bound( x 1, x m 1, a[i] ) - x;b[i] lower_bound( x 1, x m 1, b[i] 1 ) - x;}sum[0] c[0] inv[1] 1;for( int i 2;i n;i ) inv[i] (mod - mod / i) * inv[mod % i] % mod;for( int j 1;j m;j ) {int len x[j 1] - x[j];for( int i 1;i n;i ) c[i] c[i - 1] * (i len - 1) % mod * inv[i] % mod;//组合数下标不变 所以可以每一次j区间变化时再求for( int i n;i;i -- ) {//由于i与i-1及前面的挂钩所以不能从前往后更新if( a[i] j and j 1 b[i] ) {int o 1, fi 0;
//o为满足条件的个数 由于是从后往前的枚举所以o单调递增 每碰到一个合法的k o就要1for( int k i - 1;~ k;k -- ) {fi (fi sum[k] * c[o]) % mod;if( a[k] j and j 1 b[k] ) o ;}sum[i] (sum[i] fi) % mod;}}}int ans 0;for( int i 1;i n;i ) (ans sum[i]) % mod;printf( %lld\n, ans );return 0;
}