YBOI-3题解
xinxin2022 · · 题解
J3-T1
设
可以增加的次数为
注意若
难度:中位橙
J3-T2
注意到
-
-
\prod_{i=l}^r=0$,此时 $\sum_{i=l}^r a_i=k -
-
若子段里有
x 个1 ,目标为y 个,那么需修改|x-y| 次。
对于子段内
所有修改方法取
仅给出核心代码:
for(int i=1;i<=n;i++)
cin>>a[i],s[i]=s[i-1]+a[i];
while(q--){
cin>>l>>r>>k;
if(s[r]-s[l-1]==r-l+1&&r-l+1==k+1)
cout<<abs(k+1-(s[r]-s[l-1]))<<'\n';
else if(r-l+1<=k)
cout<<-1<<'\n';
else
cout<<abs(k-(s[r]-s[l-1]))<<'\n';
}
难度:高位橙
J3-T3
其实无向无环联通图就是树,题目背景里有提及推广做法,发现与中位数所求相似,于是推广做法至本题。
具体来说,问题转化为求令所有子树大小最大值最小的点。
不妨设
先钦定
记
考虑父亲节点的贡献:
此时取到最小的
给出核心代码:
void dfs(int u,int fa){
sz[u]=1;
for(int v:g[u]){
if(v==fa) continue;
dfs(v,u);
f[u]=max(f[u],sz[v]);
sz[u]+=sz[v];
}
f[u]=max(f[u],n-sz[u]);
}
难度:中位黄
S3-T1
记
不妨设
考虑讲
设目前考虑到了
此时是
考虑使用树状数组维护
这就是出题人的
其实注意到转移式中的
进一步的思考,值域不大,考虑按
给出核心代码:
//计数排序
for(int i=1;i<=n;i++) g[a[i].x].push_back(a[i].y);
for(int i=0;i<M;i++) sort(g[i].begin(),g[i].end());
for(int i=0;i<M;i++)
for(int j:g[i])
a[++p].x=i,a[p].y=j;
//dp
for(int i=1;i<=n;i++){
while(now<a[i].x) maxn=max(maxn,f[now++]);
int res=maxn+a[i].y-a[i].x+1;
f[a[i].y]=max(res,f[a[i].y]);
ans=max(ans,res);
}
难度:中位绿
S3-T2
设
特别的,
注意到转移式可以转为矩阵形式:
然后矩阵乘法即可,时间复杂度为
从另一个角度思考,设
显然走偶数单位时间才能到达,由上面的转移式可以推出(中间可以自己推,懒得写了):
按此构造矩阵,则
难度:中位蓝