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;
}