【题解】杂题选讲

news/2025/2/8 9:44:51/文章来源:https://www.cnblogs.com/fanrunze/p/18703674

杂题选讲

AT_abc350_g [ABC350G] Mediator

先考虑没有加边操作,如何回答询问?

\(fa_x\) 表示 \(x\) 的父亲,那么对 \((x,y)\) 的询问有解只有三种情况。

\(fa_x=fa_y\ne 0, fa_{fa_x}=y, fa_{fa_y}=x\)

只需要维护 \(fa\) 数组即可回答所有询问,如何维护?使用启发式合并,当两个快合并的时候,暴力修改小块的 \(fa\) ,这样没个点每次被暴力修改,所在联通块大小至少翻倍,最多被暴力修改 \(\log n\) 次。

连通性可以使用并查集维护。时间复杂度 \(\mathcal{O}(n\log n)\)

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+5,mod = 998244353;
int n,q,f[N],sz[N],ff[N];
vector<int> g[N];
void dfs(int u,int fa){f[u] = fa;for(auto v:g[u]){if(v==fa) continue;dfs(v,u);}
}
int find(int x){if(x==ff[x]) return x;return ff[x] = find(ff[x]);
}
inline void merge(int x,int y){int fx = find(x),fy = find(y);if(sz[fx]>sz[fy])swap(x, y), swap(fx, fy);dfs(x, y);sz[fy] += sz[fx], ff[fx] = fy;g[x].push_back(y), g[y].push_back(x);
}
signed main(){cin >> n >> q;for (int i = 1; i <= n; i++)sz[i] = 1, ff[i] = i;int las = 0;while (q--){int op, u, v;cin >> op >> u >> v;op = (op * (1 + las)) % mod % 2 + 1, u = (u * (1 + las)) % mod % n + 1, v = (v * (1 + las)) % mod % n + 1;if (op == 1)merge(u, v);else{las = 0;if (f[u] == f[v] && f[u] != 0)las = f[u];else if (f[f[u]] == v)las = f[u];else if (f[f[v]] == u)las = f[v];cout << las << endl;}}return 0;
}

CF1898D Absolute Beauty

首先考虑转换成区间。

image

如图,进行一次操作后,可以增加一个区间的两倍。考虑 \(l_i=\min(a_i,b_i),r_i=\max(a_i,b_i)\),此时对于任意 \(1\le i,j\le n\),可以交换 \(b_i,b_j\) 使得绝对值总和增加 \(2\times(l_i-r_j)\)。当然,当 \(l_i\le r_j\) 时,由贪心思路,此时不交换,因为交换增加不了收益。

所以,按照贪心,我们选择最大的一个 \(l_i\) 和最小的一个 \(r_j\),进行操作。当然要与 \(0\) 取最大,以免造成负面收益。

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5+9;
int t,n,a[N],b[N];
signed main()
{cin >> t;while (t--){cin >> n;for (int i = 1; i <= n; ++i) cin >> a[i];for (int i = 1; i <= n; ++i) cin >> b[i];int minn = 1e+9,maxx = 0,sum = 0;for (int i = 1; i <= n; ++i){minn = min(minn, max(a[i], b[i]));maxx = max(maxx, min(a[i], b[i]));sum += abs(a[i] - b[i]);}cout << sum + max(0LL, (maxx - minn) * 2) << endl;}return 0;
}

CF1949B Charming Meals

题意:有两个数组 \(a\)\(b\),可以任意交换进行匹配,最大化\(\min_{i=1}^{n} |a_i-b_i|\)

首先看到最小值最大,可以考虑二分。

结论性的,把所有配对分为 \(a<b\)\(a>b\) 两类,那么每一类内部肯定都是顺次匹配。换句话说,最优解就是将 \(a\) 的一个前缀和 \(b\) 等长的后缀顺次匹配,再将 \(a\) 剩余的后缀和 \(b\) 剩余的前缀顺次匹配。关键就是要寻找这个断点,暴力枚举取答案即可做到 \(\mathcal{O}(n^2)\)

考虑优化,二分答案,再二分前缀长度看这个前缀是否可以满足答案的需求,找出满足需求的最长前缀,在此基础上再看后缀是否合法,即可判定答案是否合法,从而加速到 \(\mathcal{O}(n\log^2V)\)

  • 二分做法 \(\mathcal{O}(n\log^2V)\)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
inline ll read() {ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
const int N=5050;
const int M=8e6+100;
const int mod=1e9+7;int n;
int a[N],b[N];
bool calc1(int p,int w){//判断p对红色合法for(int i=1;i<=p;i++){if(b[n-p+i]-a[i]<w) return false;}return true;
}
bool calc2(int p,int w){//判断p对蓝色是否合法for(int i=p+1;i<=n;i++){if(a[i]-b[i-p]<w) return false;}return true;
}
bool check(int w){int st=0,ed=n;while(st<ed){int mid=(st+ed+1)>>1;if(calc1(mid,w)) st=mid;else ed=mid-1;}//二分找到一个最大的让红色合法的位置preturn calc2(st,w);//判断是否能让蓝色合法
}
signed main() {int T=read();while(T--){n=read();for(int i=1;i<=n;i++) a[i]=read();for(int i=1;i<=n;i++) b[i]=read();sort(a+1,a+1+n);sort(b+1,b+1+n);	int st=0,ed=1e9;while(st<ed){//二分答案int mid=(st+ed+1)>>1;if(check(mid)) st=mid;else ed=mid-1;}printf("%d\n",st);} 
}
  • 贪心做法 \(\mathcal{O}(n^2)\)
#include<bits/stdc++.h>
using namespace std;
int t,n,a[100010],b[100010];
void solve(){cin>>n;for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<=n;i++) cin>>b[i];sort(a+1,a+n+1);sort(b+1,b+n+1); // 排序int ans=0;for(int i=1;i<=n;i++){ // 枚举折点int tmp=INT_MAX; for(int j=1;j<=i;j++)tmp=min(tmp,abs(a[j]-b[n-i+j]));for(int j=i+1;j<=n;j++)tmp=min(tmp,abs(a[j]-b[j-i]));ans=max(ans,tmp);}cout<<ans<<endl;
}
signed main(){cin>>t;while(t--)solve();return 0;
}

CF2018B Speedbreaker

策略 \(\text{X}\):按 \(a_i\) 排序,每次选择 \(a_i\) 最小的并向它扩展。(CSP-S2023 种树)

这个策略一定是正确的,证明可以考虑交换论证。

解一定是一段区间。

证明:

假设 \(x < y < z\)\(x,\,z\) 满足条件而 \(y\) 不满足条件。不妨设 \(u\) 是那个 \(y\) 走不到的点。若 \(u < y\) 则等到 \(z\) 扩展到 \(y\) 的时候显然走不到 \(u\) 了,否则 \(x\) 走不到 \(u\)

接下来我们给出断言:如果有解,则答案就是 \([i - a_i + 1,\,i + a_i - 1]\) 区间的交。

必要性显然,充分性考虑对其施策略 \(\text{X}\),失效当且仅当对于 \(a_i\) 相同的点它们的最远距离大于 \(a_i\) 了。(这种情况显然无解)

于是无解的情况和答案就讨论好了。

#include <bits/stdc++.h>
#define X first
#define Y second
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define pb push_back
using namespace std;
typedef long long int ll;
using pii = pair<int, int>;
const int maxn = 5e5 + 10, mod = 1e9 + 7;
int T, n; vector<int> e[maxn];
int main() {scanf("%d", &T);while (T--) {scanf("%d", &n); int l = 1, r = n, L = n + 1, R = 0, fg = 1;for (int i = 1, x; i <= n; i++) scanf("%d", &x), l = max(l, i - x + 1), r = min(r, i + x - 1), e[x].pb(i);for (int i = 1; i <= n; i++) {for (int x : e[i]) L = min(L, x), R = max(R, x); e[i].clear();if (R - L + 1 > i) fg = 0;}if (fg && l <= r) printf("%d\n", r - l + 1);else puts("0");}return 0;
}

CF1875D Jellyfish and Mex

首先求出原有的 \(\text {mex}\),高于 \(\text{mex}\) 的数一定不用考虑。先分析一下:如果把 \(0\) 删完,那么 \(\text{mex}\) 就一直是 \(0\) 了。但在删 \(0\) 之前可能需要先删一些更大的数使得 \(\text{mex}\) 暂时更小一点。删数一定是要么不删要么删空,且一定是从大到小删。

设计 \(f_i\) 表示把 \(i\) 删空时代价的最小值,枚举上一个删除的数字 \(j\),则有转移 \(f_i ←f_j + (\text{cnt}_i − 1) \times j + i\)

暴力转移即可,时间复杂度 \(\mathcal{O}(n^2)\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
int T, n;
map<int,int> cnt;
int dp[5005];
signed main() {ios :: sync_with_stdio(false); cin >> T;while (T--) {cin >> n;cnt.clear();memset(dp, 0x3f, sizeof(dp));for (int i = 1, tmp; i <= n; i++) {cin >> tmp;cnt[tmp]++;}int mex = 0;while (cnt[mex]) mex++;dp[mex] = 0;for (int i = mex; i >= 1; i--) {for (int j = 0; j < i; j++) {dp[j] = min(dp[j], dp[i] + (cnt[j] - 1) * i + j);}}cout << dp[0] << endl;}return 0;
} 

CF2057D Gifts Order

注意到,最优的区间一定会使最大值和最小值分别取在区间的两个端点,否则缩小区间一定更优。

因此可以看成选择 \(l,r\),最大化 \(a_r − a_l − (r − l),\ a_l − a_r − (r − l)\)

建立线段树,维护区间内最大的 \(a_r − r, −a_r − r, a_l + l, −a_l + l\),合并两个区间时,答案可能在两个区间内部(直接从左右儿子取 \(\max\) 即可),或者来自跨过区间的 \(l,r\)。对于跨过区间的 \(l,r\),尝试将左区间最大的 \(a_l + l\) 和右区间最大的 \(−a_r − r\) 拼在一起向答案作贡献即可;另一种情况则是将左区间最大的 \(−a_l + l\) 和右区间最大的 \(a_r − r\) 拼在一起向答案作贡献。

单点修改自然就很简单了。时间复杂度 \(\mathcal{O}(n \log n)\)

#include<bits/stdc++.h>
#define int long long
#define lr (ro*2)
#define rr (ro*2+1)
#define mid ((l+r)/2)
using namespace std; 
const int N=1e6;
int a[N];
int n,q;// 线段树节点结构体,包含最大值、最小值和答案
struct node
{int max1,min1; // max1和min1分别表示a[i]+i的最大值和最小值int max2,min2; // max2和min2分别表示a[i]-i的最大值和最小值int ans1,ans2; // ans1和ans2分别表示两种情况下的最大便利值
};
node tr[N*4];// 线段树的push_up操作,用于更新父节点的值
void push_up(int ro){// 更新当前节点的max1和min1tr[ro].max1=max(tr[lr].max1,tr[rr].max1);tr[ro].min1=min(tr[lr].min1,tr[rr].min1);// 更新当前节点的max2和min2tr[ro].max2=max(tr[lr].max2,tr[rr].max2);tr[ro].min2=min(tr[lr].min2,tr[rr].min2);// 更新当前节点的ans1和ans2tr[ro].ans1=max({tr[lr].ans1,tr[rr].ans1,tr[lr].max1-tr[rr].min1});tr[ro].ans2=max({tr[lr].ans2,tr[rr].ans2,tr[rr].max2-tr[lr].min2});
}// 线段树的build操作,用于构建线段树
void build(int ro=1,int l=1,int r=n){if(l==r){// 叶子节点初始化tr[ro].max1=tr[ro].min1=a[l]+l;tr[ro].max2=tr[ro].min2=a[l]-l;tr[ro].ans1=tr[ro].ans2=0;return;}// 递归构建左右子树build(lr,l,mid);build(rr,mid+1,r);// 更新当前节点push_up(ro);
}// 线段树的update操作,用于更新节点值
void update(int x,int d,int ro=1,int l=1,int r=n){if(l==r){// 更新叶子节点tr[ro].max1=tr[ro].min1=d+x;tr[ro].max2=tr[ro].min2=d-x;tr[ro].ans1=tr[ro].ans2=0;return;}// 递归更新左右子树if(x<=mid)update(x,d,lr,l,mid);elseupdate(x,d,rr,mid+1,r);// 更新当前节点push_up(ro);
}// 主函数,处理多个测试用例
signed main(){int T;cin>>T;while (T--){cin>>n>>q;for(int i=1;i<=n;i++){cin>>a[i];}// 构建线段树build();// 输出初始的最大便利值cout<<max(tr[1].ans1,tr[1].ans2)<<endl;while (q--){int p,x;cin>>p>>x;// 更新线段树update(p,x);// 输出更新后的最大便利值cout<<max(tr[1].ans1,tr[1].ans2)<<endl;}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/880713.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

十二. Redis 集群操作配置(超详细配图,配截图详细说明)

十二. Redis 集群操作配置(超详细配图,配截图详细说明) @目录十二. Redis 集群操作配置(超详细配图,配截图详细说明)1. 为什么需要集群-高可用性2. 集群概述(及其搭建)3. Redis 集群的使用4. Redis 集群故障恢复5. Redis 集群的 Jedis 开发(使用Java程序连接 Redis 同时开启集…

Docker:Docker搭建Jenkins并共用宿主机Docker部署服务(六)跨服务器远程部署前端服务

前言 继续完成跨服务器远程部署前端服务,Jenkins的搭建与插件安装可以观看上一篇文章:https://www.cnblogs.com/nhdlb/p/18561435 配置SSH远程服务器连接 这里需要安装 SSH 连接的插件,可以观看上一篇文章进行安装。开始配置SSH连接保存!! 新建视图 方便将整个项目的前端和…

一文详解文件摆渡系统是什么?企业需要什么样的文件摆渡产品?

文件摆渡系统是一种旨在实现企业内不同网络、安全域、网段之间的文件传输、同步、共享、管理与处理的工具或平台。文件摆渡系统的主要作用是确保文件能够在不同的存储环境、操作系统、应用程序或部门之间有效传递,同时保障文件的安全性、完整性和合规性。一、文件摆渡系统的核…

IvorySQL 升级指南:从 3.x 到 4.0 的平滑过渡

日前,IvorySQL 4.0 重磅发布,全面支持 PostgreSQL 17,并且增强了对 Oracle 的兼容性。关于 IvorySQL 4.0 的介绍,各位小伙伴可以通过这篇文章回顾:IvorySQL 4.0 发布:全面支持 PostgreSQL 17. 在 IvorySQL 4.0 发布后,有小伙伴私下询问升级方法,那么本篇文章就来详细描…

kvm 基础

kvm 概述 KVM(Kernel-based Virtual Machine)是一个开源虚拟化技术,它将 Linux 内核转变为一个裸金属 hypervisor。 基本概念 1. 集成于 Linux:KVM 是 Linux 内核的一部分,支持在现有的 Linux 系统上创建和管理虚拟机。 2. 虚拟化类型:KVM 支持完全虚拟化,允许运行不同操…

Ftrans数据跨境传输方案,推动数据跨境安全有序自由流动!

在全球数字经济快速发展的今天,数据跨境传输流动已成为企业国际化不可回避的重要议题。根据权威机构数据,全球跨境数据流量每年增长超过30%,企业数据出境已从简单的信息传输,演变为复杂的合规性管理。 目前,我国数据跨境传输安全管理体系已经初步构建形成。《网络安全法》…

如何打造高效、统一的供应商协同平台?

供应商协同,简单说就是把供需双方的各种“需求”找到对应的“供应”来匹配。这种“需求”和“供应”更多的不是实物,而是资讯、方法和活动。各企业需要一个供应商协同平台实现协同管理,供应链节点各企业形成共同的彼此认同的价值取向和文化理念,建立全面的战略合作伙伴关系…

RestClient 通过拦截器实现请求加密

今天我发现了一个关于请求加密的有效写法,特此分享给大家。如果你的加密需求是将请求参数也包含在内,通常情况下,我们需要先将请求体转换成 JSON 格式或其他对象类型,再使用字符串的形式进行加密操作。以下是伪代码示例,展示了这一过程的实现方法: String payloadString …

读算法简史:从美索不达米亚到人工智能时代10纠错和加密

通信系统需纠错,汉明码优化校验和;互联网设计缺安全,公钥加密RSA成基石,保障数据传输安全,现广泛用于万维网SSL。1. 纠错 1.1. 像互联网这样的通信系统,被设计成将信息的精确副本从发送方传输到接收方 1.2. 通常,接收到的信号会受到电子噪声的污染1.2.1. 噪声是任何会破…

2025 年java最新 ide 系列激活

2025 ide 激活N6IQ9MTOK0-eyJsaWNlbnNlSWQiOiJONklROU1UT0swIiwibGljZW5zZWVOYW1lIjoi5rC45LmF5Zyw5Z2AIHd3d8K3YWppaHVvwrdjb20iLCJsaWNlbnNlZVR5cGUiOiJQRVJTT05BTCIsImFzc2lnbmVlTmFtZSI6IiIsImFzc2lnbmVlRW1haWwiOiIiLCJsaWNlbnNlUmVzdHJpY3Rpb24iOiIiLCJjaGVja0NvbmN1cnJl…

INFINI Labs 产品更新 - Easysearch 增强 Rollup 能力,Console 完善 TopN 指标等

INFINI Labs 产品更新发布!此次更新,Easysearch 增强 Rollup 能力,支持更多的聚合方式;Console 完善了 TopN 的指标,支持自定义视图,并内嵌视图模板;Gateway 进行了多处优化以及修复相关 Bug 等等。欢迎下载体验,探索更多可能! INFINI Easysearch v1.10.1 INFINI Easy…