这场一开始没报名,10多分钟才交AB,然后C题WA到1个小时才靠lts和hkt告诉我二分每一段的最大差值是个假做法,然后队友在群里面@我说你怎么2300名了。。。还好D题很水秒掉了,大概只要下一点分,E题当时考场上已经写得差不多了,结果调了一上午才过。。。
先把端点离散化,按照左端点第一关键,右端点第二关键字从小到大排序。
f[i]表示恰好out到 i 的最小代价;我们可以知道新加一个套娃的新的代价tmp=f[id]+num[a[i]].l-num[id],id<=i,num为离散化之前的值
那么我们令素有f[id]-num[id]=q[id],我们其实是去id=0-i中找一个最小的q[id],然后f[i]=q[id]+num[a[i].l],有点类似单调队列DP题的套路
为了方便维护f[i],我们让q[i]=min(q[1...i])的值,sum[i]表示最小值为q[i]的总方案数
那么我们从前往后枚举套娃,每次总是考虑tmp=f[a[i].r]-num[a[i].r]; tmp能否更新 q[a[i].r].
注意每一次a[i].l的移动,我们都要维护q[a[i-1].l+1]到q[a[i].l]的值,如果前一个小于后一个,那么方案数直接覆盖,若等于,方案数就叠加。
由于要big enough,最后只要从tot到a[n].l+1枚举找f[i]=mini(f[i])的把sum[i]就行了,因为他们后面已经不能再插入了。而且这个DP过程本身也保证中间一定是不能插入的,因为求的是最小,那么中间能插入一个套娃一定会导致代价更小。而且由于i>a[n].l,sum[i]还没有进行叠加操作,就直接全部加上,不会重复。
#include<bits/stdc++.h>
#define maxl 400010
using namespace std;
const int mod=1e9+7;
const long long inf=1ll<<62;
int n,m,x,cnt,tot,mir,mxl;
long long ans;
struct node
{
int l,r;
}a[maxl];
long long f[maxl],q[maxl],sum[maxl];
int num[maxl*2];
bool in[maxl];
char s[maxl];
inline bool cmp(const node &x,const node &y)
{
if(x.l==y.l)
return x.r<y.r;
else
return x.l<y.l;
}
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&a[i].r,&a[i].l),num[++cnt]=a[i].l,num[++cnt]=a[i].r;
sort(num+1,num+1+cnt);
tot=unique(num+1,num+1+cnt)-num-1;
mir=tot+1;mxl=0;
for(int i=1;i<=n;i++)
{
a[i].l=lower_bound(num+1,num+1+tot,a[i].l)-num;
a[i].r=lower_bound(num+1,num+1+tot,a[i].r)-num;
mxl=max(a[i].l,mxl);
mir=min(a[i].r,mir);
}
sort(a+1,a+1+n,cmp);
}
inline void mainwork()
{
for(int i=1;i<=tot;i++)
sum[i]=0,f[i]=inf,q[i]=inf;
long long tmp;
sum[0]=1;f[0]=inf;q[0]=0;
for(int i=1;i<=n;i++)
{
if(a[i].l>a[i-1].l)
{
for(int j=a[i-1].l+1;j<=a[i].l;j++)
{
if(q[j]==q[j-1])
sum[j]=(sum[j-1]+sum[j])%mod;
else if(q[j]>q[j-1])
{
q[j]=q[j-1];
sum[j]=sum[j-1];
}
}
}
f[a[i].r]=q[a[i].l]+num[a[i].l];
tmp=f[a[i].r]-num[a[i].r];
if(tmp<q[a[i].r])
{
q[a[i].r]=tmp;
sum[a[i].r]=sum[a[i].l];
}
else if(tmp==q[a[i].r])
sum[a[i].r]=(sum[a[i].r]+sum[a[i].l])%mod;
}
long long mini=inf;
for(int i=n;i>=1;i--)
{
if(a[i].r>mxl)
mini=min(f[a[i].r],mini);
}
for(int i=n;i>=1;i--)
if(a[i].r>mxl)
{
if(!in[a[i].r] && f[a[i].r]==mini)
ans=(ans+sum[a[i].r])%mod;
in[a[i].r]=true;
}
}
inline void print()
{
ans=ans%mod;
printf("%lld",ans);
}
int main()
{
prework();
mainwork();
print();
return 0;
}
本文详细介绍了在比赛中解决复杂编程问题的策略与技巧,通过实例分析了如何高效地找到问题的关键,采用恰当的数据结构和算法优化解决方案。文章还讨论了如何在有限时间内调整算法以达到最优效果。
599

被折叠的 条评论
为什么被折叠?



