2023.03.05 模拟赛题解
平衡阵容
题意
由于每天挤奶,农民约翰的
农民约翰已作出了
对于每个组,他希望在您的帮助下,能确定在该组中最高的牛与最低的牛之间的高度差异。
题解
很简单的题,顺带再温习一下一下线段树。
#include <stdio.h>
#define lc(id) (id<<1)
#define rc(id) (id<<1|1)
int tr[2][200005],val[50005];
inline void push_up(int id)
{
tr[0][id]=tr[0][lc(id)]<tr[0][rc(id)]?tr[0][lc(id)]:tr[0][rc(id)];
tr[1][id]=tr[1][lc(id)]>tr[1][rc(id)]?tr[1][lc(id)]:tr[1][rc(id)];
return ;
}
inline void build(int id,int l,int r)
{
if(l==r)
{
tr[0][id]=tr[1][id]=val[l];
return ;
}
int mid=l+r>>1;
build(lc(id),l,mid);
build(rc(id),mid+1,r);
push_up(id);
return ;
}
inline int max(int x,int y)
{
return x>y?x:y;
}
inline int min(int x,int y)
{
return x<y?x:y;
}
inline int maxquery(int id,int ql,int qr,int l,int r)
{
if(ql<=l&&r<=qr)
{
return tr[1][id];
}
int mid=l+r>>1,ret=-1;
if(mid>=ql)
ret=max(ret,maxquery(lc(id),ql,qr,l,mid));
if(mid<qr)
ret=max(ret,maxquery(rc(id),ql,qr,mid+1,r));
return ret;
}
inline int minquery(int id,int ql,int qr,int l,int r)
{
if(ql<=l&&r<=qr)
{
return tr[0][id];
}
int mid=l+r>>1,ret=10000005;
if(mid>=ql)
ret=min(ret,minquery(lc(id),ql,qr,l,mid));
if(mid<qr)
ret=min(ret,minquery(rc(id),ql,qr,mid+1,r));
return ret;
}
int main()
{
int l,r,i,n,q;scanf("%d %d",&n,&q);
for(i=1;i<=n;++i)
{
scanf("%d",val+i);
}
build(1,1,n);
while(q--)
{
scanf("%d %d",&l,&r);
printf("%d\n",maxquery(1,l,r,1,n)-minquery(1,l,r,1,n));
}
return 0;
}
滑板鞋
题意
你在魅力之都购买了一双时尚的滑板鞋,你非常兴奋地到处摩擦!
这显然是一个很简单的问题,但是
题解
此题中有
预处理
#include <stdio.h>
int f[100005][65],a[100005];
int main()
{
int n,m,i,lg,base,cnt;
long long k;
scanf("%d %d",&n,&m);
for(i=1;i<=n;++i)
{
scanf("%d",a+i);
f[i][0]=a[i];
}
for(lg=1;lg<65;++lg)
{
for(i=1;i<=n;++i)
f[i][lg]=f[f[i][lg-1]][lg-1];
}
while(m--)
{
cnt=0;
scanf("%d %lld",&base,&k);
while(k)
{
if(k&1)
{
base=f[base][cnt];
}
k>>=1;
++cnt;
}
printf("%d\n",base);
}
return 0;
}
图
题意
有一个
:从 出发走 条边,路径权值和。 :从 出发走 条边,路径权值最小值。
题解
感觉和前一题没有本质区别,典得不能再典。
#include <stdio.h>
#include <algorithm>
using std::min;
long long f[3][100005][65],a[100005];
int vec[65];
int cnt=0;
int main()
{
int n,i,lg,base;
long long k,s,m;
scanf("%d %lld",&n,&k);
for(i=0;i<n;++i)
{
scanf("%d",a+i);
f[2][i][0]=a[i];
}
for(i=0;i<n;++i)
{
scanf("%d",a+i);
f[0][i][0]=f[1][i][0]=a[i];
}
for(lg=1;lg<65;++lg)
{
for(i=0;i<n;++i)
{
f[0][i][lg]=f[0][i][lg-1]+f[0][f[2][i][lg-1]][lg-1];
f[1][i][lg]=min(f[1][i][lg-1],f[1][f[2][i][lg-1]][lg-1]);
f[2][i][lg]=f[2][f[2][i][lg-1]][lg-1];
}
}
while(k)
{
vec[++cnt]=std::__lg(k&-k);
k-=k&-k;
}
for(auto __base=0;__base<n;++__base)
{
base=__base;
s=0;m=1ll<<60;
for(i=1;i<=cnt;++i)
{
s+=f[0][base][vec[i]];
m=min(f[1][base][vec[i]],m);
base=f[2][base][vec[i]];
}
printf("%lld %lld\n",s,m);
}
return 0;
}
最小线段覆盖
题意
题解
考虑倍增。
套路地,
#include <stdio.h>
int n,m,l,r,i,j,ans;
int f[500005][65];
const int V=500000;
inline int max(int x,int y)
{
return x>y?x:y;
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d %d",&l,&r);
f[l][0]=max(f[l][0],r);
}
for(i=1;i<=V;++i)
f[i][0]=max(f[i][0],f[i-1][0]);
for(j=1;j<65;++j)
for(i=0;i<=V;++i)
f[i][j]=f[f[i][j-1]][j-1];
while(m--)
{
scanf("%d %d",&l,&r);
ans=1;
for(i=30;i>=0;i--)
if(f[l][i]<r)
{
ans+=1<<i;
l=f[l][i];
}
if(f[l][0]>=r)
printf("%d\n",ans);
else
puts("-1");
}
return 0;
}
GCD 查询
题意
给出
题解
困难的。
首先我们需要观察到一个性质,
简要证明:
- 显然有
。 - 若
,那么必定 - 那么对于任意一个
, 作为 时, 至多会有 种。
由此该性质得到了就简单的证明。其实实际上应该远远跑不到
然后考虑如何统计答案。
套路地枚举左端点,由于
方便叙述,设
- 若
,则对答案 产生 的贡献。 - 若
,则对答案 产生 的贡献。 - 以此类推。
记录答案的话,由于此题 std::map
吧。
分析一下复杂度,
本来用线段树实现,但是似乎常数太大,大数据会超时,改 ST 表实现。
#include <map>
#include <stdio.h>
#define lc(id) (id<<1)
#define rc(id) (id<<1|1)
std::map<int,long long> rem;
int lg[100005],st[100005][25];
//int tr[400005],val[100005];
inline int gcd(int x,int y)
{
return !y?x:gcd(y,x%y);
}
/*
inline void push_up(int id)
{
tr[id]=gcd(tr[lc(id)],tr[rc(id)]);
return ;
}
inline void build(int id,int l,int r)
{
if(l==r)
{
tr[id]=val[l];
return ;
}
int mid=l+r>>1;
build(lc(id),l,mid);
build(rc(id),mid+1,r);
push_up(id);
return ;
}
inline int query(int id,int ql,int qr,int l,int r)
{
if(ql<=l&&r<=qr)
return tr[id];
int mid=l+r>>1,lans,rans;
lans=rans=0;
if(ql<=mid)
lans=query(lc(id),ql,qr,l,mid);
if(mid<qr)
rans=query(rc(id),ql,qr,mid+1,r);
return gcd(lans,rans);
}
*/
inline int query(int l, int r) {
static int _lg;
_lg=lg[r-l+1];
return gcd(st[l][_lg],st[r-(1<<_lg)+1][_lg]);
}
int main()
{
int nxt,j,n,i,now,l,q,x,r,mid;scanf("%d",&n);
for(i=1;i<=n;++i)
scanf("%d",st[i]);
for(i=2;i<=100000;++i)
lg[i]=lg[i>>1]+1;
for(j=1;(1<<j)<=n;++j)
for(i=1;i+(1<<j)-1<=n;++i)
st[i][j]=gcd(st[i][j-1],st[i+(1<<j-1)][j-1]);
// build(1,1,n);
// for(i=1;i<=n;++i,puts(""))
// for(int j=i;j<=n;++j)
// printf("%d ",query(1,i,j,1,n));
for(i=1;i<=n;++i)
{
nxt=i;
while(nxt<=n)
{
now=query(i,nxt);
l=nxt;r=n;
while(l<=r)
{
mid=l+r>>1;
if(query(i,mid)!=now)
r=mid-1;
else
l=mid+1;
}
rem[now]+=l-nxt;
nxt=l;
}
}
scanf("%d",&q);
while(q--)
{
scanf("%d",&x);
printf("%lld\n",rem[x]);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】