NOIP提高组模拟赛10
这套题咕咕咕咕咕了好久,还是决定先写一点吧
A. 第零题
从到,在处死了,那么与从到死的次数是一样的,也就是说可以向上走到一下的最后一次死的点,最后这一段统计一下需不需要多死一次就好了,树上倍增记录的第级死亡点,1级死亡点时候记录路径二分查找即可
code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=200005;
struct edge{
int to,val,net;
}e[maxn<<1|1];
int head[maxn],tot,n,k;
void add(int u,int v,int w){
e[++tot].net=head[u];
head[u]=tot;
e[tot].to=v;
e[tot].val=w;
}
int fa[maxn][21],dep[maxn],jd[maxn][21],top,rem[maxn];
long long cos[maxn],sum[maxn];
int ef(int x){
int l=1,r=x;
while(l<r){
int mid=(l+r)>>1;
if(sum[x]-sum[mid]>=k)l=mid+1;else r=mid;
}
return rem[l-1];
}
void dfs(int x,int fx){
rem[++top]=x;sum[top]=sum[top-1]+cos[x];
jd[x][0]=ef(top);fa[x][0]=fx;dep[x]=dep[fx]+1;
for(int i=head[x];i;i=e[i].net){
int v=e[i].to;if(v==fx)continue;
cos[v]=e[i].val;dfs(v,x);
}
--top;
}
int LCA(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=20;i>=0;--i)if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
if(x==y)return x;
for(int i=20;i>=0;--i)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int ask(int s,int t){
int lca=LCA(s,t);
int ans=0;
for(int i=20;i>=0;--i){
if(dep[lca]<dep[jd[s][i]]){
ans+=(1<<i);
s=jd[s][i];
}
if(dep[lca]<dep[jd[t][i]]){
ans+=(1<<i);
t=jd[t][i];
}
}
if(dep[jd[s][0]]>=dep[lca])++ans,s=jd[s][0];
if(dep[jd[t][0]]>=dep[lca])++ans,t=jd[t][0];
int sum=0;
while(s!=lca)sum+=cos[s],s=fa[s][0];
while(t!=lca)sum+=cos[t],t=fa[t][0];
if(sum>=k)++ans;
return ans;
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<n;++i){
int u,v,w;scanf("%d%d%d",&u,&v,&w);
add(u,v,w);add(v,u,w);
}
//rem[0]=1;
dfs(1,1);
for(int i=1;i<=20;++i)for(int x=1;x<=n;++x)fa[x][i]=fa[fa[x][i-1]][i-1],jd[x][i]=jd[jd[x][i-1]][i-1];
int q;scanf("%d",&q);
for(int i=1;i<=q;++i){
int s,t;scanf("%d%d",&s,&t);
printf("%d\n",ask(s,t));
}
return 0;
}
B. 第负一题
cao年代久远,忘了,还得重新看题解。。。。。。
分治+DP
每次计算跨过中点的区间的贡献
向左,选/不选的最大值
向右,选/不选的最大值
对答案的贡献为
并不好求,转化一下
设
对答案贡献转化为
对 排序,单调指针扫一遍就行了
code
#include <cstring>
#include <cstdio>
#include<algorithm>
using namespace std;
const long long maxn=200005;
const long long mod=998244353;
long long n,a[maxn];
const long long inf=0x3f3f3f3f3f3f3f;
long long fl[maxn],fr[maxn],ll[maxn][2],rr[maxn][2];
long long dp[maxn][2],ans;
void work(int l,int r){
if(l==r){
ans=(ans+a[l]);
return;
}
int mid=(l+r)>>1;work(l,mid);work(mid+1,r);
//向左,不选mid
dp[mid][0]=0;dp[mid][1]=-inf;
for(int i=mid-1;i>=l;--i)dp[i][0]=max(dp[i+1][0],dp[i+1][1]),dp[i][1]=dp[i+1][0]+a[i],ll[i][0]=max(dp[i][0],dp[i][1]);
//向左,选mid
dp[mid][0]=-inf;dp[mid][1]=a[mid];
for(int i=mid-1;i>=l;--i)dp[i][0]=max(dp[i+1][0],dp[i+1][1]),dp[i][1]=dp[i+1][0]+a[i],ll[i][1]=max(dp[i][0],dp[i][1]);
//向右,不选mid+1
dp[mid+1][0]=0;dp[mid+1][1]=-inf;
for(int i=mid+2;i<=r;++i)dp[i][0]=max(dp[i-1][0],dp[i-1][1]),dp[i][1]=dp[i-1][0]+a[i],rr[i][0]=max(dp[i][0],dp[i][1]);
//向右,选mid+1
dp[mid+1][0]=-inf;dp[mid+1][1]=a[mid+1];
for(int i=mid+2;i<=r;++i)dp[i][0]=max(dp[i-1][0],dp[i-1][1]),dp[i][1]=dp[i-1][0]+a[i],rr[i][1]=max(dp[i][0],dp[i][1]);
ll[mid][0]=0;ll[mid][1]=a[mid];
rr[mid+1][0]=0;rr[mid+1][1]=a[mid+1];
for(int i=l;i<=mid;++i)fl[i]=max(ll[i][1]-ll[i][0],0ll),ans=(ans+ll[i][0]*(r-mid))%mod;
for(int i=mid+1;i<=r;++i)fr[i]=max(rr[i][1]-rr[i][0],0ll),ans=(ans+rr[i][0]*(mid-l+1))%mod;
sort(fl+l,fl+mid+1);sort(fr+mid+1,fr+r+1);
int pl=l,pr=mid+1;
while(pl<=mid){
while(fr[pr]<=fl[pl]&&pr<=r)ans=(ans+fr[pr]*(pl-l))%mod,++pr;
ans=(ans+fl[pl]*(pr-mid-1))%mod;++pl;
}
while(pr<=r)ans=(ans+fr[pr]*(mid-l+1))%mod,++pr;
return;
}
int main(){
scanf("%lld",&n);
for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
work(1,n);
printf("%lld\n",ans);
return 0;
}
C. 第负二题
这就是我咕咕咕咕咕了这篇题解这么长时间的原因
这道题啊,暴力水了90pts,然后正解呢,咕咕咕咕咕咕
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】