题解 P3643 【[APIO2016]划艇】
sky_of_war · · 题解
同步更新于我的博客:APIO2016划艇
Solution
首先有一种比较好想的状态表示:
这种状态表示有一个很严重的问题在于,第二维的范围是
Lemma. 从区间
[0,L] 中取n 个数,要求所有非零数严格递增,则方案数为\binom{L+n}{n} 。
Proof. 对于没有
考虑从这个序列取
回到原来的问题,由于第
这东西显然可以前缀和处理。设
于是
关于实现,每次递推好组合数防止过多的取模就可以了。
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<bits/stdc++.h>
#define getchar getchar_unlocked
#define putchar putchar_unlocked
constexpr int MAXN = 5e2 + 10;
typedef long long ll;
constexpr int mo = 1e9 + 7;
using namespace std;
int n, tot, a[MAXN], b[MAXN], num[MAXN << 1], g[MAXN], C[MAXN], inv[MAXN];
template <class T>
inline void _read(T &x)
{
x = 0;
char t = getchar();
while(!isdigit(t)) t = getchar();
while(isdigit(t))
{
x = x * 10 + t - '0';
t = getchar();
}
}
template <class T>
inline void print(T x)
{
if(x < 0)
{
putchar('-');
x = -x;
}
if(x > 9)
print(x / 10);
putchar(x % 10 + '0');
}
template <class T>
inline int fastmod(T x)
{
if (x >= mo) return x - mo; else return x;
}
int main()
{
_read(n);
inv[1] = 1;
for(int i = 2; i <= n; ++i) inv[i] = (ll)(mo - mo / i) * inv[mo % i] % mo;
for(int i = 1; i <= n; ++i)
{
_read(a[i]), _read(b[i]);
num[++tot] = a[i];
num[++tot] = b[i] + 1;
}
sort(num + 1, num + 1 + tot);
tot = unique(num + 1, num + 1 + tot) - num - 1;
for(int i = 1; i <= n; ++i)
{
a[i] = lower_bound(num + 1, num + 1 + tot, a[i]) - num;
b[i] = lower_bound(num + 1, num + 1 + tot, b[i] + 1) - num;
}
C[0] = 1;
g[0] = 1;
for(int j = 1; j < tot; ++j)
{
int len = num[j + 1] - num[j];
for(int i = 1; i <= n; ++i) C[i] = (ll)C[i - 1] * (len + i - 1) % mo * inv[i] % mo;
for(int i = n; i; --i)
if(a[i] <= j && j + 1 <= b[i])
{
int f = 0, m = 1, c = len;
for(int p = i - 1; p >= 0; --p)
{
f = fastmod(f + (ll)c * g[p] % mo);
if(a[p] <= j && j + 1 <= b[p]) c = C[++m];
}
g[i] = (g[i] + f) % mo;
}
}
int ans = 0;
for(int i = 1; i <= n; ++i) ans = fastmod(ans + g[i]);
print(ans);
return 0;
}