codeforces1197E Culture Code

本文详细介绍了在比赛中解决复杂编程问题的策略与技巧,通过实例分析了如何高效地找到问题的关键,采用恰当的数据结构和算法优化解决方案。文章还讨论了如何在有限时间内调整算法以达到最优效果。

这场一开始没报名,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;
}

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值