191030CSP模拟DAY2

今天又差点垫底了,下次要加油啊

T1:序列

传送门

首先,看到题目所给条件, a 1 + ⋯ + a r ⟩ = 0 \left.\mathrm{a}_{1}+\cdots+\mathrm{a}_{\mathrm{r}}\right\rangle= 0 a1++ar=0 b 1 + ⋯ + b r ⟩ = 0 \left.b_{1}+\cdots+b_{r}\right\rangle= 0 b1++br=0,可想到用前缀和记录,即当满足 s u m a r − s u m a l − 1 > = 0 suma_{r}-suma_{l-1}>=0 sumarsumal1>=0 s u m b r − s u m b l − 1 > = 0 sumb_{r}-sumb_{l-1}>=0 sumbrsumbl1>=0,此时,题目已转化为一道三维偏序问题,
{ i ≤ j ≤ n s u m a i ≤ s u m a j s u m b i ≤ s u m b j \left\{\begin{array}{l}{i \leq j \leq n} \\ {suma_{i} \leq suma_{j}} \\ {sumb_{i} \leq sumb_{j}}\end{array}\right. ijnsumaisumajsumbisumbj

而多维偏序问题,我们多用CDQ分治(我并不会 )或先以 a a a为第一关键词, b b b为第二关键词,将 s u m sum sum数组排序,(记得排序前先离散化),接着以 b b b为下标, i d id id为值,用树状数组维护最小值即可。

代码:

#include<bits/stdc++.h>
#define int long long
#define db double
#define re register
#define cs const
using namespace std;
inline int read()
{
	int x=0,f=1;
	char ch;
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	return f*x;
}
struct node
{
	int a,b,num;
}s[1000003];
bool cmp(cs node &x,cs node &y)
{
	if(x.a!=y.a)	return x.a<y.a;
	return x.b<y.b;
}
int n,w[1000003],iii,ans,tree[1000003];
int lowbit(int x)
{
	return x&(-x);
}
void update(int i,int x)
{
	while(i<=iii)
	{
		tree[i]=min(tree[i],x);
		i+=lowbit(i);
	}
}
int query(int x)
{
	int ans=0x3f3f3f3f;
	while(x)
	{
		ans=min(ans,tree[x]);
		x-=lowbit(x);
	}
	return ans;
}
signed main()
{
	n=read();
	memset(tree,0x3f,sizeof(tree));
	for(re int i=1;i<=n;++i)	s[i].a=read()+s[i-1].a,w[i]=s[i].a;
	for(re int i=1;i<=n;++i)	s[i].b=read()+s[i-1].b,w[i+n]=s[i].b;
	sort(w+1,w+1+2*n);
	iii=unique(w+1,w+1+2*n)-w-1;
	for(re int i=1;i<=iii;++i)
	{
		s[i].a=lower_bound(w+1,w+1+iii,s[i].a)-w;
		s[i].b=lower_bound(w+1,w+1+iii,s[i].b)-w;
		s[i].num=i;
	}	
	sort(s+1,s+1+n,cmp);
	for(re int i=1;i<=n;++i)
	{
		update(s[i].b,s[i].num);
		ans=max(ans,s[i].num-query(s[i].b));
	}
	printf("%d",ans);
}

T2:二叉搜索树

传送门

看到这道题,一眼就能看出暴力,而在暴力过程中,我们可以发现这其实是一道区间 D P DP DP,方程为: f l , r = min ⁡ ( f l , p − 1 + f p + 1 , r + s u m ( l , r ) ) f_{l, r}=\min \left(f_{l, p-1}+f_{p+1, r}+s u m(l, r)\right) fl,r=min(fl,p1+fp+1,r+sum(l,r))而正常的算法需要 n ³ n³ n³的复杂度,则需要优化,这是区间类(2D1D)动规,我们可以由证明得其决策是具有单调性的,

伪证:设 [ l , r ] [l,r] [l,r]区间的决策点为p,则 [ l , r + 1 ] [l,r+1] [l,r+1]区间的决策点会出现在p点右方,而 [ l − 1 , r ] [l-1,r] [l1,r]区间的决策点会出现在p点左方,则满足单调性

严谨证明需要用四边形不等式(我不会 )

代码:

#include<bits/stdc++.h>
#define int long long
#define db double
#define re register
#define cs const
using namespace std;
inline int read()
{
	int x=0,f=1;
	char ch;
	while(ch>'9'||ch<'0')
	{
		if(ch=='-')	f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=x*10+ch-'0';
		ch=getchar();
	}
	return f*x;
}
int n,f[5005][5005],d[5005][5005],a[5005];
signed main()
{
	n=read();
	for(re int i=1;i<=n;++i)	a[i]=read()+a[i-1],d[i][i]=i,f[i][i]=a[i]-a[i-1];
	for(re int len=1;len<=n;++len)
		for(re int i=1,j=i+len;j<=n;++i,++j)
		{
			f[i][j]=1e18;
			for(re int k=d[i][j-1];k<=d[i+1][j];++k)
			{
				if(f[i][k-1]+f[k+1][j]+a[j]-a[i-1]<f[i][j])
				{
					f[i][j]=f[i][k-1]+f[k+1][j]+a[j]-a[i-1];
					d[i][j]=k;
				}
			}
		}
	printf("%lld",f[1][n]);
}

T3:走路

传送门

咕咕咕!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值