题目链接http://codeforces.com/contest/1197/problem/E
题意
n个套娃,每个套娃有两个属性
i
n
in
in和
o
u
t
out
out,当且仅当
o
u
t
i
<
=
i
n
j
out_i<=in_j
outi<=inj时,
i
i
i套娃可以被
j
j
j套娃套住。
定义一串套娃足够长:不可以再添加别的套娃
定义一串套娃的空闲体积:
i
n
i
1
+
(
i
n
i
2
−
o
u
t
i
1
)
+
.
.
.
+
(
i
n
i
k
−
o
u
t
i
k
−
1
)
in_{i_1}+(in_{i_2}-out_{i_1})+...+(in_{i_k}-out_{i_{k-1}})
ini1+(ini2−outi1)+...+(inik−outik−1)
问:当套娃足够长,空闲体积最小是多少,有多少个足够长的套娃空闲体积等于最小值。
题解
首先观察空闲体积的式子,除了最后一个,其他的贡献都是负值。这就说明,每多套一个小的套娃,答案肯定是变小。
如果直接给套娃建边,边数肯定会爆炸。所以我们考虑离散,把套娃按照
i
n
in
in来进行分类。
设立一个
f
[
i
]
f[i]
f[i]记录在
i
i
i以内套娃的最小贡献(肯定是负数),
c
n
t
[
i
]
cnt[i]
cnt[i]记录
f
[
i
]
f[i]
f[i]的组成个数。逐步枚举
i
i
i以及
i
n
=
=
i
in==i
in==i的套娃,更新数组。
注意只有在没有更大的套娃的情况下,才能更新答案。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> piir;
const ll N=4e5+7;
const ll mod=1e9+7;
struct Node{
ll in,out;
bool operator<(const Node k)const{
return out<k.out;
}
}a[N];
ll mx=0;
ll xx[N],tot;
vector<ll>vc[N];
ll f[N],cnt[N];
int main(){
ll n;
scanf("%lld",&n);
memset(f,125,sizeof(f));
for(ll i=1;i<=n;i++){
scanf("%lld%lld",&a[i].out,&a[i].in);
xx[++tot]=a[i].in;
xx[++tot]=a[i].out;
mx=max(a[i].in,mx);
}
sort(xx+1,xx+1+tot);
tot=unique(xx+1,xx+1+tot)-xx-1;
sort(a+1,a+1+n);
for(ll i=1;i<=n;i++){
a[i].in=lower_bound(xx+1,xx+1+tot,a[i].in)-xx;
a[i].out=lower_bound(xx+1,xx+1+tot,a[i].out)-xx;
}
for(ll i=1;i<=n;i++){
vc[a[i].in].push_back(a[i].out);
}
ll ans=f[0],num=0;
f[0]=0,cnt[0]=1;
for(ll i=1;i<=tot;i++){
if(f[i-1]<f[i]){
f[i]=f[i-1];
cnt[i]=cnt[i-1];
}
else if(f[i-1]==f[i]){
cnt[i]=(cnt[i]+cnt[i-1])%mod;
}
if(cnt[i]==0) continue;
for(auto j:vc[i]){
ll tmp=f[i]+xx[i];
if(ans>tmp&&xx[j]>mx){
ans=tmp;
num=cnt[i];
}
else if(ans==tmp&&xx[j]>mx){
num=(num+cnt[i])%mod;
}
if(f[j]>tmp-xx[j]){
f[j]=tmp-xx[j];
cnt[j]=cnt[i];
}
else if(f[j]==tmp-xx[j]){
cnt[j]=(cnt[j]+cnt[i])%mod;
}
}
}
printf("%lld\n",num);
}