OIFHA 2026 模拟赛第五试
冲浪( \(surf\) )
鲨鱼噶呜·古拉正在网上冲浪。她的冲浪路线可以用数轴来模拟,起点在\(1\)位置,终点在\(L\)位置。
当她在\(x\)位置时,如果跳跃能力是\(k\),她就能跳到\([x,x+k]\)内的任意整数位置。她的跳跃能力初值是\(1\)。
不过冲浪路上可不平坦,有\(n\)个障碍区间,每个障碍用区间\([l,r]\)表示,意味着她不能到达\([l,r]\)区间内的任何位置。
路上还散落着\(m\)个能量道具。第\(i\)个道具位于\(x_i\)位置,能量为\(v_i\)。当古拉到达\(x_i\)位置时,可以选择拾取道具来增加\(v_i\)点跳跃能力。同一个位置可能有多个道具,她可以自由选择拾取或忽略任一道具。
请帮她算一下,最少需要收集多少个道具才能冲浪到终点\(L\)?如果无法抵达终点,请输出\(−1\)。
数据范围
| 测试点 | \(n\le\) | \(m\le\) | \(L\le\) | 特殊性质 |
|---|---|---|---|---|
| \(1 \sim 4\) | \(10\) | \(10\) | \(10^9\) | |
| \(5 \sim 7\) | \(100\) | \(10^5\) | \(10^5\) | |
| \(8 \sim 10\) | \(10^5\) | \(100\) | \(10^7\) | |
| \(11 \sim 13\) | \(10^5\) | \(10^5\) | \(10^7\) | |
| \(14 \sim 16\) | \(10^5\) | \(10^5\) | \(10^9\) | A |
| \(17 \sim 20\) | \(10^5\) | \(10^5\) | \(10^9\) |
特殊性质A:对\(\forall i\),有\(r_i+1<l_{i+1}\)
对于100%的数据,\(t \le 10,1 \le n,m \le 10^5,1\le \sum n,\sum m \le 2 \times 10^5,1 \le l_i,r_i,x_i < L \le 10^9\)
- 看数据范围可知:算法时间复杂度近似 \(O(n\log_2n)\)。
- 路线遍历每一个,便可在 \(1~\) 此时位置的能量道具中任选。
- 大的能量道具优先选。
- 只有障碍长度大于跳跃能力才不可跳过。
由此可得解题方法。
- 将障碍和道具(可看作 \([x_{i},x_{i}]\) )按 \(l_{i}\)排序。
- 顺序遍历。
- 遇到道具便加入大根堆。
- 遇到障碍分两种情况。
- 跳跃能力够,直接忽略。
- 不够,不停从大根堆中弹出道具,直到跳跃能力够,累计上答案,再忽略。
- 输出答案。
本题 \(O(n\log_2n)\) 可解。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 500005
int t,n,m,l,jump,pd,cnt,nn;
priority_queue<int>q;
struct PT{int l,r;}p[N],pt[N];
bool cmp(PT a,PT b){return a.l<b.l;}
signed main(){
freopen("surf.in","r",stdin);
freopen("surf.out","w",stdout);
scanf("%lld",&t);
while(t--){
scanf("%lld%lld%lld",&n,&m,&l),jump=1,cnt=nn=0;
for(int i=1;i<=n;i++) scanf("%lld%lld",&p[i].l,&p[i].r),p[i].r=min(p[i].r,l);
for(int i=1;i<=m;i++) scanf("%lld%lld",&pt[i].l,&pt[i].r);
sort(p+1,p+n+1,cmp),sort(pt+1,pt+m+1,cmp);
pd=(p[1].l!=1);
for(int i=1;i<=n;i++){if(p[i].l<p[nn].r) p[nn].r=max(p[nn].r,p[i].r);else p[++nn]=p[i];}
n=nn;
while(!q.empty()) q.pop();
for(int i=1,j=1;i<=n&&p[i].l<=l&&pd;i++){
while(j<=m&&pt[j].l<p[i].l) q.push(pt[j].r),j++;
while(j<=m&&pt[j].l<=p[i].r) ++j;
while(jump<=p[i].r-p[i].l+1){
if(q.empty()){pd=0;break;}
jump+=q.top();q.pop(),cnt++;
}
}
if(pd) printf("%lld\n",cnt);
else printf("-1\n");
}
return 0;
}
\(n\) 黄蛋( \(negg\) )
给定 \(n\) 个同心圆环,环的编号从外向内依次增大,每个环从12点方向开始,被平均分成了 \(p_i\) 个区域,区域编号从12点方向开始,沿顺时针方向增大,第一个区域编号为\(1\)。
同一个环内的相邻区域的交界处设有障碍,不可以穿越;而相邻的两个环之间的交界处没有障碍,可以穿越。记第 \(i\) 个环的第 \(j\) 个区域坐标为 \((i,j)\)。定义两个区域\(x\)和\(y\)连通,当且仅当从\((i_x,j_x)\)出发,经过若干区域 \((i_{z_1} , j_{z_1})\) ,\((i_{z_2},j_{z_2})\) …… 后,能够抵达 \((i_{y},j_{y})\),中间经过的任意区域 \((i_{z_k},j_{z_k})\) 都必须满足 \(min(i_x,i_y)\le i_{z_k}\le max(i_x,i_y)\)。
现给出 \(q\) 个操作,操作共有两种类型:对于第一种操作,给定两个区域坐标 \((i_x,j_x)\) 和 \((i_y,j_y)\) ,请你判断这两个区域是否连通;对于第二种操作,将第 \(k\) 个环重新分割成 \(q\) 份。
说明/提示
请选择较快的输入输出方式。
数据范围:
| 数据点 | \(n\le\) | \(q\le\) | \(p\le\) | 特殊性质 |
|---|---|---|---|---|
| \(1 \sim 4\) | \(10^2\) | \(10^2\) | \(10^4\) | |
| \(5 \sim 6\) | \(10^5\) | \(10^2\) | \(10^7\) | |
| \(7 \sim 8\) | \(10^2\) | \(10^5\) | \(10^7\) | |
| \(9 \sim 10\) | \(10^6\) | \(10^6\) | \(10^9\) | A、B |
| \(11 \sim 15\) | \(10^6\) | \(10^6\) | \(10^9\) | B |
| \(16 \sim 20\) | \(10^6\) | \(10^6\) | \(10^9\) |
特殊性质A:所有 \(p_i\) 满足 \(p_i=i+1\)
特殊性质B:保证不存在第二种操作
对于100%的数据:\(1\le T\le10\) , \(\sum n,\sum q\le 10^6\) , \(1\le p_i\le10^9\) , \(1\le i_x , i_y\le n\) , \(1\le j_x\le p_{i_x}\) ,\(1\le j_y\le p_{i_y}\)。
- 看数据范围又可知:算法时间复杂度近似(就只能是!) \(O(n\log n)\)。
- 分析相邻两个环在什么情况下不可穿越:在与 \(p_{i}\) 和 \(p_{i+1}\) 相关时,只有 \(\frac{l}{p_{i}}=\frac{r}{p_{i+1}}\),即 \(r*p_{i}=l*p_{i+1}\),即 \(l\) 为 \(\frac{p_{i}}{gcd(p_{i},p_{i+1})}\) 的倍数时不可穿越。
- 分析相邻 \(k\) 个环在什么情况下不可穿越:在与 \(p_{i}\) 和 \(p_{j}\) 相关时,只有 \(\frac{l_{i}}{p_{i}}=\frac{l_{i+1}}{p_{i+1}}=...=\frac{l_{j}}{p_{j}}\),即 \(l\) 为 \(\frac{p_{i}}{gcd(p_{i},p_{i+1},...,p_{j})}\) 的倍数时不可穿越,设 \(\frac{x}{gcd(p_{y},p_{y+1},...,p_{z})}\) 为 \(g_{x,y,z}\)。
- 分析两个区域 \((i_{x}, j_{x})\) 和 \((i_{y}, j_{y})\) 在什么情况下可穿越:与 \(i_{x}\) 和 \(i_{y}\) 相关,只有 \(\lfloor\frac{j_{x}}{g_{x,x,y}}\rfloor=\lfloor\frac{j_{y}}{g_{y,x,y}}\rfloor\) 的倍数时可穿越。
- 问题转移到如何 \(O(\log{n})\) 求出 \(gcd(p_{i},p_{i+1},...,p_{j})\):线段树大法好,能做到 \(O(\log n)\)。
此题应该解了( \(?\) ),常数很大,可能要卡常,时间复杂度 \(O(n\log^n)\)。
为什么这个时间复杂度不是 \(O(n\log^2 n)\)
- 对于修改操作,将值修改成 \(x\),则每进行 \(gcd\) 中的一次操作,即对于 \(gcd(x,y)\) 变成 \(gcd(y,x \bmod y)\),则 \(x\) 至少缩小为原本的 \(\frac{1}{2}\),所以修改操作时间复杂度为 \(O(\log n)\)。
- 对于查询操作。设线段树查询操作中能便利到的 \(gcd\) 的值为 \(g_{1},g_{2},...,g_{k},\),其合并的顺序大概为 \(gcd(gcd(...gcd(gcd(g_{1},g_{2}),g_{3}),...),gcd(...gcd(gcd(g_{k},g_{k-1}),g_{k-2}),...))\),\(gcd(...gcd(gcd(g_{1},g_{2}),g_{3}),...)\) 合并的 \(gcd\) 的操作数最多为 \(\log{g_{1}}+log{n}\),\(gcd(...gcd(gcd(g_{k},g_{k-1}),g_{k-2}),...)\) 合并的 \(gcd\) 的操作数最多为 \(\log{g_{k}}+log{n}\),最后一次合并操作数最多为 \(\log{max(g_{1},g_{k})}\),总时间复杂度为 \(O(\log n)\) 级别的。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 2000005
int t,n,q,p[N],op,x,y,a,b,s[N<<2];
void build(int rt,int l,int r){
if(l==r){s[rt]=p[l];return ;}
int mid=(l+r)>>1;
build(rt<<1,l,mid),build((rt<<1)+1,mid+1,r);
s[rt]=__gcd(s[rt<<1],s[(rt<<1)+1]);
}
void change(int rt,int l,int r,int x,int c){
if(l==r){s[rt]=c;return ;}
int mid=(l+r)>>1;
if(mid>=x) change(rt<<1,l,mid,x,c);
else change((rt<<1)+1,mid+1,r,x,c);
s[rt]=__gcd(s[rt<<1],s[(rt<<1)+1]);
}
int searchh(int rt,int l,int r,int ls,int rs){
if(l==ls&&r==rs){return s[rt];}
int mid=(l+r)>>1,ans=0;
if(mid>=ls) ans=__gcd(ans,searchh(rt<<1,l,mid,ls,min(rs,mid)));
if(mid<rs) ans=__gcd(ans,searchh((rt<<1)+1,mid+1,r,max(mid+1,ls),rs));
return ans;
}
void solve(int x,int y,int a,int b){
int g=searchh(1,1,n,min(x,a),max(x,a));
if(y/(p[x]/g)+(y%(p[x]/g)!=0)==b/(p[a]/g)+(b%(p[a]/g)!=0))printf("Yes\n");
else printf("No\n");
}
signed main(){
freopen("negg.in","r",stdin);
freopen("negg.out","w",stdout);
scanf("%lld",&t);
while(t--){
scanf("%lld%lld",&n,&q);
for(int i=1;i<=n;i++) scanf("%lld",&p[i]);
build(1,1,n);
while(q--){
scanf("%lld",&op);
if(op==1)scanf("%lld%lld%lld%lld",&x,&y,&a,&b),solve(x,y,a,b);
else scanf("%lld%lld",&x,&y),change(1,1,n,x,y),p[x]=y;
}
}
return 0;
}
萌树(\(cute\))
题目背景
树的根会变,但树依然挺立——你的逻辑也该如此坚韧。
题目描述
太宇得到了一棵树,它有\(n\)个节点。对于选定的根节点\(r\),太宇想要计算这棵树的可爱度。
考虑树中所有由\(k\)个不同节点组成的集合。对于每个这样的集合,计算在以\(r\)为根时的最近公共祖先(LCA),将所有得到的LCA节点编号求和,那么这棵树的可爱度就是\(f(r)\),即
在发现了树的可爱度后,太宇对树的萌度产生了兴趣!萌度定义为:
可惜,太宇在忙。请帮帮他,计算这棵树的萌度吧!
输入格式
输入格式第一行包含测试用例数量\(t\)。
每个测试用例的第一行包含两个整数\(n\)和\(k\)——树中顶点数和要选的不同节点数。
接下来 \(n−1\) 行描述树的边。每行包含两个整数 \(u\) 和 \(v\) ,表示顶点 \(u\) 和顶点 \(v\) 之间有一条边。保证这些边构成一棵树。
输出样例
输出格式对于每个测试用例,输出一个整数表示萌度,由于答案可能很大,你需要将答案对998244353取模。
样例输入
3
2 2
1 2
5 3
1 2
1 3
1 4
1 5
6 3
1 2
1 3
2 4
2 5
3 6
样例输出
3
110
324
数据范围
| 测试点 | \(n\le\) | \(k\le\) | 特殊性质 |
|---|---|---|---|
| \(1 \sim 3\) | \(12\) | \(12\) | |
| \(4 \sim 7\) | \(2\times 10^3\) | \(3\) | |
| \(8 \sim 13\) | \(2\times10^3\) | \(2\times10^3\) | |
| \(14 \sim 15\) | \(2\times10^5\) | \(2\times10^5\) | A |
| \(16 \sim 17\) | \(2\times10^5\) | \(2\times10^5\) | B |
| \(18 \sim 25\) | \(2\times10^5\) | \(2\times10^5\) |
特殊性质A:对任意的\(i\),都有\(u_i=i,v_i=i+1\)
特殊性质B:对任意的\(i\),都有\(u_i=x,1\le x\le n\)
对于100%的数据,\(1 \le t \le 100 ,1 \le \sum n \le 2 \times 10^5,2 \le k \le n \le 2\times 10^5\)
样例说明
针对第二个样例,选择的3个结点分别为{1,2,3},在根节点为1,2,3,4,5的情况下,LCA(1,2,3)分别为1,2,3,1,1,和为8
{1,2,4}:1,2,1,4,1,和为9
{1,2,5}:1,2,1,1,5,和为10
{1,3,4}:1,1,3,4,1,和为10
{1,3,5}:1,1,3,1,5,和为11
{1,4,5}:1,1,1,4,5,和为12
{2,3,4}:1,2,3,4,1,和为11
{2,3,5}:1,2,3,1,5,和为12
{2,4,5}:1,2,1,4,5,和为13
{3,4,5}:1,1,3,4,5,和为14,总和为110。
看数据范围又可知:算法时间复杂度是 \(O(n)\),换根 \(dp\),解了,时间复杂度正确。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define N 200005
#define md 998244353
int t,n,k,head[N],tot=1,jc[N],nyjc[N],sz[N],ans,anss;
struct EDGE{int v,nt;}edge[N<<2];
void addedge(int x,int y){
edge[tot].v=y,edge[tot].nt=head[x],head[x]=tot++;
edge[tot].v=x,edge[tot].nt=head[y],head[y]=tot++;
}
void exgcd(int a,int b,int &x,int &y){
if(b==0){x=1,y=0;return ;}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
int ny(int w){
int x,y;
w=(w%md+md)%md;
exgcd(w,md,x,y);
return (x%md+md)%md;
}
int c(int x,int y){
if(x>y) return 0;
return jc[y]*nyjc[x]%md*nyjc[y-x]%md;
}
void dfs(int x,int f){
sz[x]=1;
for(int i=head[x];i;i=edge[i].nt){
int y=edge[i].v;
if(y==f) continue;
dfs(y,x);
if(sz[x]+sz[y]>=k) ans=(ans+(c(k,sz[x]+sz[y])-c(k,sz[y])-c(k,sz[x]))%md*x%md)%md;
sz[x]+=sz[y];
}
}
void dfss(int x,int f){
ans=(ans+(c(k,n)-c(k,sz[x])-c(k,n-sz[x]))%md*x%md)%md;
anss=(anss+ans)%md;
for(int i=head[x];i;i=edge[i].nt){
int y=edge[i].v;
if(y!=f) ans=(ans-(c(k,n)-c(k,sz[y])-c(k,n-sz[y]))%md*x%md)%md,dfss(y,x),ans=(ans+(c(k,n)-c(k,sz[y])-c(k,n-sz[y]))%md*x%md)%md;
}
ans=(ans-(c(k,n)-c(k,sz[x])-c(k,n-sz[x]))%md*x%md)%md;
}
signed main(){
freopen("cute.in","r",stdin);
freopen("cute.out","w",stdout);
scanf("%lld",&t),jc[0]=nyjc[0]=1;
for(int i=1;i<=N-5;i++) jc[i]=jc[i-1]*i%md;
nyjc[N-5]=ny(jc[N-5]);
for(int i=N-6;i;i--) nyjc[i]=nyjc[i+1]*(i+1)%md;
while(t--){
scanf("%lld%lld",&n,&k),ans=anss=0;
memset(head,0,sizeof(head)),tot=1;
for(int i=1,x,y;i<n;i++)cin>>x>>y,addedge(x,y);
dfs(1,0),dfss(1,0);
cout<<(anss+md)%md<<endl;
}
return 0;
}
\(T4\) 不会
浙公网安备 33010602011771号