2019辞旧迎新模拟赛--题解报告

2019辞旧迎新模拟赛——题解报告

劭星

第一题:rmq问题(乱搞)

30分做法:暴力枚举

假定查询L,R最值

代码如下:

for(int i=l;i<=r;i++)

{

maxx=max(a[i],maxx);

minn=min(a[i],minn);

}

 

满分做法:

什么分块啊、树状数组啊、线段树啊……都可以

反正这儿没有设定太严格的空间限制

 

 

第二题:魔法树(最小dfs序+二分)

这里一定要注意,这里给出的m是自动修复能力值,

所以你还要自己用n减去m求你最多可以销毁多少个平台

 

接下来就要求出最小dfs序了

(当然,你也可以直接在树上跑,这样子浪费时间,大概得个50分吧)

接着,把求得的序列映射出来,然后对映射出来的做一个二分答案

怎么说呢……就是跳石头那题差不多吧

 

PS:原本出题思路:就是想出个dfs序的

但是审题的时候发现满足递增序列……woc

于是就可以把最小dfs序替换成快排了的

嘤嘤嘤

那些老老实实写了最小dfs序的同学给你们点赞

 

第三题:装水(思维题)

我也不知道多少分,反正是暴力的做法;

每次删除数组中的前导和后缀的0,然后统计剩下的有多少个0小于等于

下一轮每个数依次减去1

这样的话,假设最高高度为m,那么时间复杂度就是O(n*m)了

不用想,还是过不了

 

100分做法:舍去常数的话是O(n)

对于每一个水槽的边,可以说其容积为tag(当前水槽的边上面有多少单位的水),可以是0

第一步:从左往右扫一遍,找到当前位置左边最高的水槽的边

第二步:从右往左扫一遍,找到当前位置右边最高的水槽的边

第三步:对于每个位置,在那个位置左右最高的边之中取最小值

这三步是什么意思呢?

就是说,一个区域(通俗直观看上去就是“水坑”)能够装水,取决于区域两边的最高峰

可以自己画图理解一下,然后对于这个区域装的最高(注意是高度)的的高度则取决于最低的那个峰(类似于木桶效应)

 

第四步:用第三步得到的最小值减去当前位置的高度,就可以得到这个水槽的边上方有多少个单位体积的水(tag)啦!注意:如果差小于1,就不用累计进答案,continue即可

 

第五步:累计每个水槽的边的tag,求出答案

 

 

还行吧~

 

第四题:对战牌组(类似数学)

这题也是只有满分的情况

做法:

先将字符做一个映射,比如说A—1,B—2等等

然后这题就变成一道对数列的处理问题了

题目的意思就是说:求出下一组排列

这里参(zhai)照(chao)一下我的blog:https://blog.csdn.net/qq_36976937/article/details/84977839

2333,顺便帮本蒟蒻推广一下

 

 

 

 

解法:这里还是一个所谓的数学解法

这里比较玄学,我尽量讲明白吧。

 

先来看解题步骤,最后再解释:

拿序列3 4 2 1举例子

1.从右往左找到第一个反递增的数a,将这个数所在的位置(下标)记为pos

在这个例子里头,a=3,pos=1

 

2.从右到左找到比a大的第一个数b

在这里,b=4

 

3.交换a和b

例子中的序列就变成了:4 3 2 1

 

4.将pos右边的所有数都翻转(最后一位变为第一位,倒数第二位变为第二位……)

例子中的序列就变成了4 1 2 3

 

此时的序列就是所求的解

 

怎么样,玄学吧【笑】

看到这里,还是请自行思考5~10分钟

一步一步理解(也可以画图,也可以论证,理解就行)

 

我的理解:

 

我理解了蛮久,大概也是10min这样才看懂。

 

第一步,找到a和pos

我们反过来理解,a是右到左反递增数,那么说,从右到左在pos之前的一直都是保持递增的序列

ps:如果没找到就直接输出-1,自己想想为什么

 

第二步,找到b

这一步还是要连着第三步一起讲

 

第三步:交换a和b

这一步就是使新得到的序列比原序列大,连第二步来说,就是让新的到的序列在其他比原序列大的序列中尽可能小,因为b是第一个比a大的数

 

第四步:pos后面的翻转

因为pos后的都是递增,翻转后就也是递增,不过方向不一样,翻转后的递增是使b为关键的序列最小

 

我尽力解释清楚了

 

附上每一题std代码:

第一题:

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;
int read()
{
	int x=0,f=1;	char ch=getchar();
	while(ch<'0' || ch>'9'){	if(ch==-1)	f=-1;	ch=getchar();}
	while(ch>='0' && ch<='9')	{x=x*10+ch-'0'; ch=getchar();}
	return  x*f;
}
int n,m;
struct node{
	int l,r;
	int minn,maxx;
	int lazy;
}tree[400000+10];
int ans=-1;
int ans2=1000000000;
void down(int k);
void build(int l,int r,int k)
{
	tree[k].l=l,tree[k].r=r;
	if(l==r)
	{
		cin>>tree[k].maxx;
		tree[k].minn=tree[k].maxx;
		return ;
	}
	int m=(l+r)>>1;
	build(l,m,2*k);
	build(m+1,r,k*2+1);
	tree[k].maxx=max(tree[2*k].maxx,tree[2*k+1].maxx);
	tree[k].minn=min(tree[2*k].minn,tree[2*k+1].minn);
}
void find(int k,int x,int y)
{
	if(tree[k].l>=x && tree[k].r<=y)
	{
		ans=max(ans,tree[k].maxx);
		ans2=min(ans2,tree[k].minn);
		return  ;
	}
	if(tree[k].lazy)	down(k);
	int mid=(tree[k].l+tree[k].r)>>1;
	if(x<=mid)	find(2*k,x,y);
	if(y>mid)		find(2*k+1,x,y);
}
void down(int k)
{
    tree[k*2].lazy+=tree[k].lazy;
    tree[k*2+1].lazy+=tree[k].lazy;
    tree[k*2].maxx+=tree[k].lazy*(tree[k*2].r-tree[k*2].l+1);
    tree[k*2+1].maxx+=tree[k].lazy*(tree[k*2+1].r-tree[k*2+1].l+1);
    tree[k].lazy=0;
}
int main()
{
	freopen("rmq.in","r",stdin);
	freopen("rmq.out","w",stdout);
	n=read();
	build(1,n,1);
	m=read();
	for(int i=1;i<=m;i++)
	{
		int x=read(),y=read();
		ans=-1;
		find(1,x,y);
		cout<<ans<<" "<<ans2<<endl;
	}
	return 0;
}

看那个帅哥写了懒标记!~

 

第二题:

#include <iostream>
#include <vector>

using namespace std;

int n,m;
int a[10001]={0};
bool vis[10001];
vector<int> nod[10001];
int from[10001];
int d[10001],w[10001];
int read()
{
	int x=0;char ch=getchar();
	while(ch<'0' || ch>'9')	ch=getchar();
	while(ch>='0' && ch<='9')	{x=x*10+ch-'0';	ch=getchar();}
	return x;
	}
int cnt=1;
void dfs(int now)
{
	if(d[now]==0)
	{
		if(cnt==n)	return ;
		dfs(from[now]);
	}
	else
	{
		int minn=INT_MAX;
		for(unsigned int i=0;i<nod[now].size();i++)
			if(!vis[nod[now][i]])
				minn=min(minn,nod[now][i]);
		vis[minn]=true;
		d[now]--;d[minn]--;from[minn]=now;
		cnt++;
		a[cnt]=w[minn];
		dfs(minn);
	}
}
void start()
{
	n=read();m=read();
	m=n-m;
	for(int i=1;i<=n;i++)
		w[i]=read();
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read();
		nod[u].push_back(v);
		nod[v].push_back(u);
		d[u]+=1,d[v]+=1;
		}
	a[1]=w[1];
	vis[1]=true;
}
bool check(int far)
{
	int cnt=0;
	int now=0;
	for(int i=1;i<n;i++)
		if(a[i]-a[now]<far)
			cnt++;
		else
			now=i;
	if(cnt>m)	return false;
	else		return true;
}
void doit()
{
	int l=1,r=a[n];
	int ans;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(	check(mid) )
			ans=mid,l=mid+1;
		else
			r=mid-1;
	}
	cout<<ans<<endl;
}
int main()
{
	freopen("magic.in","r",stdin);
	freopen("magic.out","w",stdout);
	start();
	dfs(1);
	doit();
	return 0;
}

第三题:

 

#include <iostream>

using namespace std;

int n;
int a[100000001]={0};
int read()
{
    int x=0,f=1;    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-')    f=-1;ch=getchar();}
    while(ch>='0' && ch<='9')   {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
int main()
{
    freopen("hold.in","r",stdin);
    freopen("hold.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    int maxx=a[1];
    int max_l[100000001];
    for(int i=1;i<=n;i++)
    {
        max_l[i]=maxx;
        maxx=max(maxx,a[i]);
    }
    maxx=a[n];
    int ans=0;
    for(int i=n;i>=1;i--)
    {
        int	tmp=min(maxx,max_l[i])-a[i];
        if(tmp>0)   ans+=tmp;
        maxx=max(maxx,a[i]);
    }
    cout<<ans;
    return 0;
}

 

第四题:

#include <iostream>
#include <algorithm>

using namespace std;

int read()
{
    int x=0,f=1;	char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-')    f=-1;ch=getchar();}
    while(ch>='0' && ch<='9')   {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
int n;
void doit()
{
	int a[10001];
	int m=read();
	for(int i=1;i<=m;i++)
	{
		char ch;	cin>>ch;
		a[i]=ch-'A'+1;
	}
	int pos;
	int aa;
	int f=0;
	for(int i=m;i>=1;i--)
		if(a[i]<a[i+1])	
			{aa=a[i],pos=i;f=1;break;}
	if(!f)	{cout<<"No"<<endl;return ;}
	for(int i=m;i>=1;i--)
		if(a[i]>aa)	
			{swap(a[i],a[pos]);break;}
	for(int i=1;i<=pos;i++)
		cout<<char(a[i]+'A'-1)<<" ";
	for(int i=m;i>pos;i--)
		cout<<char(a[i]+'A'-1)<<" ";
	cout<<endl;
}
int main()
{
	freopen("card.in","r",stdin);
	freopen("card.out","w",stdout);
	n=read();
	for(int i=1;i<=n;i++)
		doit();
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值