题面
Sol
sto
s
t
o
fdf
f
d
f
sto
s
t
o
fateice
f
a
t
e
i
c
e
显然,如果一个区间包含了另一个区间,那么它的最小值不会有贡献,直接去掉
考虑枚举最大值
k
k
求出所有区间满足最小值小于等于的概率,设为
P[k]
P
[
k
]
那么
k
k
的贡献就是,相当于差分了一下
然后考虑算出
P[k]
P
[
k
]
设
f[i]
f
[
i
]
表示到
i
i
时,所有右端点都小于等于的区间都满足要求的概率
枚举右端点在
i
i
的所有左端点
枚举在哪里弄一个小于等于
k
k
的
枚举的这个点之前的随便选,而后面的只能选大于
k
k
的
这样才能做到不重复计算,因为如果后面的也随便选,那么会和之前的有交集
然后这是的,居然过了
n,x<=2000
n
,
x
<=
2000
把上面的转移式拆一下,把
f[l−1]∗(1−kx)−l
f
[
l
−
1
]
∗
(
1
−
k
x
)
−
l
做个前缀和就好了
特别注意如果
i=l
i
=
l
并且
k=x
k
=
x
时,
(1−kx)i−l
(
1
−
k
x
)
i
−
l
要当成
1
1
那么特判一下就好了
orz
o
r
z
fateice
f
a
t
e
i
c
e
orz
o
r
z
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(2005);
const int Zsy(666623333);
IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
int n, x, Q, tp, f[_], g[_], ans, first[_], nxt[_], inv;
struct Query{
int l, r;
IL int operator <(RG Query B) const{
return l != B.l ? l < B.l : r < B.r;
}
} tmp[_], q[_];
IL int Pow(RG ll x, RG ll y){
RG ll ret = 1;
for(; y; y >>= 1, x = x * x % Zsy)
if(y & 1) ret = ret * x % Zsy;
return ret;
}
IL void Upd(RG int &x, RG int y){
x += y;
if(x >= Zsy) x -= Zsy;
}
IL int Sum(RG int l, RG int r){
return (g[r] - (l < 0 ? 0 : g[l]) + Zsy) % Zsy;
}
IL int Calc(RG int v){
RG int p1 = 1LL * inv * v % Zsy, p2 = (1 + Zsy - p1) % Zsy, p3 = Pow(p2, Zsy - 2);
Fill(g, 0), Fill(f, 0), g[0] = p3, f[0] = 1;
for(RG int i = 1; i <= n; ++i){
for(RG int p = first[i]; p; p = nxt[p]){
if(i > q[p].l) Upd(f[i], 1LL * Sum(q[p].l - 2, i - 2) * p1 % Zsy * Pow(p2, i) % Zsy);
Upd(f[i], 1LL * f[i - 1] * p1 % Zsy);
}
if(!first[i]) f[i] = f[i - 1];
g[i] = g[i - 1], Upd(g[i], 1LL * f[i] * Pow(p3, i + 1) % Zsy);
}
return f[n];
}
int main(RG int argc, RG char *argv[]){
n = Input(), x = Input(), tp = Input(), inv = Pow(x, Zsy - 2);
for(RG int i = 1; i <= tp; ++i) tmp[i] = (Query){Input(), Input()};
sort(tmp + 1, tmp + tp + 1);
for(RG int i = 1; i <= tp; ++i){
while(q[Q].r >= tmp[i].r) --Q;
if(tmp[i].l > q[Q].l) q[++Q] = tmp[i];
}
for(RG int i = 1; i <= Q; ++i) nxt[i] = first[q[i].r], first[q[i].r] = i;
for(RG int i = 1, lst = 0; i <= x; ++i){
RG int now = Calc(i);
ans = (ans + 1LL * i * ((now - lst + Zsy) % Zsy) % Zsy) % Zsy;
lst = now;
}
printf("%d\n", ans);
return 0;
}