191109CSP模拟DAY2

今天他们在外面校庆,我们在机房考试,qwq

T1:排兵布阵(BJOI2019)

传送门

这道题有个很明显的策略就是,每个城堡要么放要么不放,而且放的话必须达到最小的那个值 ∗ 2 + 1 *2+1 2+1,所以我们在读入时即可先处理,然后由于题目中有个 s = 1 s=1 s=1我们可以联想到 01 01 01背包,然后写完 40 p t s 40pts 40pts以后,我们可以继续联想到组合背包(虽然我没学过 ),将每个城堡中每个人派遣的人数排序,然后就是一个赤裸裸的背包了,算贡献时 ∗ i *i i即可。

代码:

#include<bits/stdc++.h>
#define re register
#define db double
#define ll long long
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 f[20005];
int s,n,m,a[105][105];
int main()
{
	s=read();
	n=read();
	m=read();
	for(re int i=1;i<=s;++i)
		for(re int j=1;j<=n;++j)	a[j][i]=read();		
	for(re int i=1;i<=n;++i)
	{
		sort(a[i]+1,a[i]+1+s);
		for(re int j=m;j;--j)
			for(re int k=1;2*a[i][k]+1<=j&&k<=s;++k)
			{
				f[j]=max(f[j],f[j-1-2*a[i][k]]+i*k);
			}
	}
	printf("%d",f[m]);
	return 0;
}

T2:小X的二叉树

传送门

这道题正解是 O ( n l o g n ) O(nlogn) O(nlogn)的复杂度,而我用 O ( n ) O(n) O(n)的贪心搞了过去,实乃人生之大幸。

由于是中序遍历,所以先左子树,根节点,最后右子树,所以我们可以想到,在这个长度为 n n n的序列中,必有一个根节点,并且,在这个序列中,它是除了它自身以外所有点的祖先,而在它的左侧的是左子树,右侧的是右子树,我们分治下去即可,每产生一个区间就判断是否合法即可。

但是这样很明显是 O ( n ² ) O(n²) O(n²)的复杂度,不能 A C AC AC,所以这时候我们可以用玄学的启发式合并,从左右两端同时向中间扫,满足条件就递归下去,就成了 O ( n l o g n ) O(nlogn) O(nlogn)的复杂度,我不会证 ,但简略地说就是通过一个小的区间,确定一个大的区间。

然后用线段树维护最大最小值即可。

代码:

#include<bits/stdc++.h>
#define db double
#define re register
#define cs const
#define N 2000005
#define mid (l+r)/2
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 T,n,k,val[N];
struct node
{
	int maxx,minn;
}tree[N*4];
void build(int k,int l,int r)
{
	if(l==r)
	{
		tree[k].minn=val[l];
		tree[k].maxx=val[l];
		return;
	}
	build(k<<1,l,mid);
	build(k<<1|1,mid+1,r);
	tree[k].minn=min(tree[k<<1].minn,tree[k<<1|1].minn);
	tree[k].maxx=max(tree[k<<1].maxx,tree[k<<1|1].maxx);
}
void query(int k,int l,int r,int x,int y,int &mi,int &ma)
{
	if(x<=l&&r<=y)
	{
		mi=tree[k].minn;
		ma=tree[k].maxx;
		return;
	}
	int mii=0x3f3f3f3f;
	int maa=0;
	if(x<=mid)	query(k<<1,l,mid,x,y,mii,maa);

	if(y>mid)
	{
		query(k<<1|1,mid+1,r,x,y,mi,ma);
		mi=min(mi,mii);
		ma=max(ma,maa);
		return;
	}	
	mi=mii;
	ma=maa;
}
bool solve(int l,int r)
{
	if(l>r||l==r)	return true;
	int ll=l,rr=r;
	int mi,ma;
	query(1,1,n,l,r,mi,ma);
	while(ll<=rr)
	{
		if(val[ll]-mi<=k&&ma-val[ll]<=k)	return solve(l,ll-1)&&solve(ll+1,r);
		if(val[rr]-mi<=k&&ma-val[rr]<=k)	return solve(l,rr-1)&&solve(rr+1,r);
		++ll;
		--rr;
	}
	return false;
}
int main()
{
	int size=40<<20;
    __asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size));
	T=read();
	while(T--)
	{
		n=read();
		k=read();
		for(re int i=1;i<=n;++i)	val[i]=read();
		build(1,1,n);
		if(solve(1,n))	puts("Yes");
		else puts("No");
	}
	exit(0);
}

T3:特技飞行(GXOI2019)

传送门

这道题涉及了很多知识点。

首先:我们 a , b a,b a,b c c c是可以分开考虑的,所以我们先处理 a 和 b a和b ab,题目要求我们求出最大最小值,且飞机到达终点后必须满足在起点的相对顺序,所以 a 和 b a和b ab谁大,我们就尽量做这个动作。

  1. a > b a>b a>b,我们尽量做 a a a,所以我们就所有的逆序对轮换一遍即可。
  2. a < b a<b a<b,我们尽量做 b b b,交换次数为 n − n- n置换数,因为只将每个环中的数交换一遍即可,而每个环是独立的,每个环交换 l e n − 1 len-1 len1次即可。

接下来,我们考虑 c c c的问题,而这个斜着的四边形我们看起来很不舒服,所以我们就曼哈顿转切比雪夫,再用扫描线算出其贡献即可。

最后由于交点数 < 5 e 5 <5e5 <5e5所以我们可以暴力求出,直接用解析式即可。

代码咕咕咕

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值