(回滚莫队)洛谷 P10268 符卡对决 题解
居然还没调出来?感觉是数据类型的问题,真是吓人。先把思路写一下吧。
题意
灵梦一共有 n n n 张符卡,每张卡都有一个能力值,对于第 i i i 张卡,它的能力值为 a i a_i ai,现在她想从中选出两张符卡并使用它们,灵梦发现,如果她同时打出了两张符卡 i , j i, j i,j,这两张符卡造成的伤害将会是 a i × a j a_i\times a_j ai×aj。
这些符卡之间有能力的冲突,灵梦会告诉你这些符卡的兼容性,具体而言这些符卡之间有 m m m 条关系,这些关系表明某两张符卡之间是兼容的,注意,如果符卡 i , j i, j i,j 兼容且符卡 j , k j, k j,k 兼容,那么符卡 i , k i, k i,k 也是兼容的,如果打出的两张符卡之间不是兼容的,那么它们造成的伤害为 0 0 0。
她很好奇符卡之间的兼容性会造成什么样的影响,所以她会询问你 q q q 次,每次告诉你一对正整数 l , r l, r l,r,意味着只有编号在区间 [ l , r ] [l, r] [l,r] 内的关系才会生效。
灵梦不想把魔理沙虐得太惨,所以她会随机从所有符卡中选出两张不同的符卡来打出,她想知道每次询问造成的伤害的期望值对 1 0 9 + 7 10^9 + 7 109+7 取模后是多少。
输入
4 4 4
5 8 2 7
3 1
1 4
3 2
1 4
2 4
1 2
2 3
3 3
输出
500000012
833333349
500000012
666666674
样例解释
对于第三组询问,只有 ( 1 , 4 ) , ( 2 , 3 ) (1, 4), (2, 3) (1,4),(2,3) 两对符卡之间是兼容的。
如果选择的符卡是 ( 1 , 2 ) (1, 2) (1,2),那么它们不兼容,伤害值为 0 0 0,这种情况的概率是 1 6 \dfrac16 61。
如果选择的符卡是 ( 1 , 3 ) (1, 3) (1,3),那么它们不兼容,伤害值为 0 0 0,这种情况的概率是 1 6 \dfrac16 61。
如果选择的符卡是 ( 1 , 4 ) (1, 4) (1,4),它们兼容,伤害值为 a 1 × a 4 = 35 a_1\times a_4 = 35 a1×a4=35,这种情况的概率是 1 6 \dfrac16 61。
如果选择的符卡是 ( 2 , 3 ) (2, 3) (2,3),它们兼容,伤害值为 a 2 × a 3 = 16 a_2\times a_3 = 16 a2×a3=16,这种情况的概率是 1 6 \dfrac16 61。
如果选择的符卡是 ( 2 , 4 ) (2, 4) (2,4),那么它们不兼容,伤害值为 0 0 0,这种情况的概率是 1 6 \dfrac16 61。
以此类推,最终的期望值是 17 2 \dfrac{17}{2} 217,其在模 1 0 9 + 7 10^9 + 7 109+7 意义下等于 500000012 500000012 500000012。
1 ≤ n , q ≤ 1 0 5 , 1 ≤ m ≤ 2 n , 1 ≤ a i ≤ 1 0 9 , 1 ≤ l i ≤ r i ≤ m , 1 ≤ u i , v i ≤ n 1\le n, q\le 10^5, 1\le m\le 2n, 1\le a_i\le 10^9, 1\le l_i\le r_i\le m, 1\le u_i, v_i\le n 1≤n,q≤105,1≤m≤2n,1≤ai≤109,1≤li≤ri≤m,1≤ui,vi≤n。
思路
给定询问区间,说编号在 [ l , r ] [l,r] [l,r] 的符卡可以产生关系,仅当两张符卡兼容,考虑用莫队维护区间数据。
肯定是并查集的,但是如果做全局并查集肯定不正确,因为有可能区间内有两张符卡不兼容,而与询问区间外的一张卡产生关系。
因此为了保证正确性,我们需要动态地维护并查集。因为双指针需要移动,因此需要写一个可撤销并查集——进入知识盲区了,不过就是对需要撤销的点对打标记,后进先撤销,那不就是栈序吗。
struct dsu
{stack<pll>stk;ll fa[N],siz[N];ll fz(ll x){while(x!=fa[x])x=fa[x]=fa[fa[x]];return x;}void join(ll u,ll v,bool tag)//tag:是否将被撤销 {u=fz(u),v=fz(v);if(u==v){if(tag)stk.push(mk(0,0));return;}if(siz[u]<siz[v])swap(u,v);//规定从属先后if(tag)stk.push({u,v});siz[u]+=siz[v];fa[v]=u;}void cancel()//撤销 {ll u=stk.top().fi,v=stk.top().se;stk.pop();fa[v]=v;siz[u]-=siz[v];}void reset(){for(ll i=1;i<=n;i++){fa[i]=i;siz[i]=1;sum[i]=a[i];}}
};
我们发现撤销其实并不好更新答案,因为栈里面维护的是所在连通块内祖先的点对,无法对应原始下标,因此考虑使用回滚莫队。就是将双指针拆成 l ∼ b r l\sim br l∼br 和 b r + 1 ∼ r br+1\sim r br+1∼r,右区间部分永久化,左区间部分回滚……这就是回滚莫队的套路了,可以前往上一篇文章粗略学习。
题目要求造成的伤害的期望值对 1 0 9 + 7 10^9 + 7 109+7 取模后是多少,拆掉期望就是 E = a n s n ( n − 1 ) 2 E=\frac{ans}{\frac {n(n-1)}{2}} E=2n(n−1)ans, a n s ans ans 为当前询问造成的最大伤害。
计算 a n s ans ans 就是妥妥的数学题了。我们假设一组连通块内有 a , b , c , d a,b,c,d a,b,c,d,答案就是 a b + b c + c d + d a ab+bc+cd+da ab+bc+cd+da,但是这样不好在并查集合并时直接查询,考虑式子变形:
= 1 2 ( 2 a b + 2 a c + 2 a d + 2 b c + 2 b d + 2 c d ) =\frac {1}{2}(2ab+2ac+2ad+2bc+2bd+2cd) =21(2ab+2ac+2ad+2bc+2bd+2cd)
= 1 2 [ a 2 + b 2 + c 2 + d 2 + 2 a b + 2 a c + 2 a d + 2 b c + 2 b d + 2 c d − ( a 2 + b 2 + c 2 + d 2 ) ] =\frac{1}{2}[a^2+b^2+c^2+d^2+2ab+2ac+2ad+2bc+2bd+2cd-(a^2+b^2+c^2+d^2)] =21[a2+b2+c2+d2+2ab+2ac+2ad+2bc+2bd+2cd−(a2+b2+c2+d2)]
= 1 2 [ a ( a + b + c + d ) + b ( a + b + c + d ) + c ( a + b + c + d ) + d ( a + b + c + d ) − ( a 2 + b 2 + c 2 + d 2 ) ] =\frac{1}{2}[a(a+b+c+d)+b(a+b+c+d)+c(a+b+c+d)+d(a+b+c+d)-(a^2+b^2+c^2+d^2)] =21[a(a+b+c+d)+b(a+b+c+d)+c(a+b+c+d)+d(a+b+c+d)−(a2+b2+c2+d2)]
= 1 2 [ ( a + b + c + d ) 2 − ( a 2 + b 2 + c 2 + d 2 ) ] =\frac{1}{2}[(a+b+c+d)^2-(a^2+b^2+c^2+d^2)] =21[(a+b+c+d)2−(a2+b2+c2+d2)]
即连通块内战斗力总和的平方,减去各符卡平方的和,再除以 2 2 2。
各符卡平方的和在计算答案数组时,再统一减去,可以先把动态答案 r e t ret ret 的初值修改为 ∑ i = 1 n a i 2 \displaystyle\sum_{i=1}^{n}a_i^2 i=1∑nai2,计算答案时方便得到相反数。
具体细节见代码:
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mk make_pair
#define pll pair<ll,ll>
#define fi first
#define se second
const ll N=1e5+9,mod=1e9+7;
ll n,t,m,a[N];
ll bSize,cnt_b,bel[N<<1],bl[N],br[N];
ll ret,ans[N];
ll sm[N];
struct dsu
{stack<pll>stk;ll fa[N],siz[N],sum[N];//sum:块内权值总和 ll fz(ll x){while(x!=fa[x])x=fa[x]=fa[fa[x]];return x;}void join(ll u,ll v,ll &ANS,bool tag)//tag:是否将被撤销 {u=fz(u),v=fz(v);if(u==v){if(tag)stk.push(mk(0,0));return;}if(siz[u]<siz[v])swap(u,v);if(tag)stk.push({u,v});ANS=((ANS-sum[u]*sum[u]%mod-sum[v]*sum[v]%mod)%mod+mod)%mod;siz[u]+=siz[v];fa[v]=u;sum[u]=(sum[u]+sum[v])%mod;ANS=(ANS+sum[u]*sum[u]%mod)%mod;}void cancel()//撤销 {ll u=stk.top().fi,v=stk.top().se;stk.pop();fa[v]=v;siz[u]-=siz[v];sum[u]=((sum[u]-sum[v])%mod+mod)%mod;}void reset(){for(ll i=1;i<=n;i++){fa[i]=i;siz[i]=1;sum[i]=a[i];}}
}d,d2;
struct bian
{ll u,v;
}b[N<<1];
struct que
{ll l,r,id;
}q[N];
bool cmp(que x,que y)
{if(bel[x.l]!=bel[y.l])return bel[x.l]<bel[y.l];return x.r<y.r;
}
void init()
{bSize=sqrt(t);//对边数分块 cnt_b=t/bSize;if(t%bSize)cnt_b++;for(ll i=1;i<=t;i++)bel[i]=(i-1)/bSize+1;for(ll i=1;i<=cnt_b;i++){bl[i]=(i-1)*bSize+1;br[i]=i*bSize;}br[cnt_b]=t;
}
void add_r(ll x,ll &ANS)
{d.join(b[x].u,b[x].v,ANS,0);
}
void add_l(ll x,ll &ANS)
{d.join(b[x].u,b[x].v,ANS,1);
}
void del_l(ll x)
{d.cancel();
}
ll qpow(ll x,ll k)
{ll ret=1;while(k){if(k&1)ret=ret*x%mod;x=x*x%mod;k>>=1;}return ret;
}
int main()
{scanf("%lld%lld%lld",&n,&t,&m);ll inv=qpow(n*(n-1),mod-2),sqs=0;for(ll i=1;i<=n;i++){scanf("%lld",&a[i]);sqs=(sqs+a[i]*a[i]%mod)%mod;}d.reset();d2.reset();init();ret=sqs;for(ll i=1;i<=t;i++){ll u,v;scanf("%lld%lld",&u,&v);b[i]=(bian){u,v};}for(ll i=1;i<=m;i++){ll l,r;scanf("%lld%lld",&l,&r);q[i]=(que){l,r,i};}sort(q+1,q+m+1,cmp);ll l=1,r=0;for(ll i=1;i<=m;i++){if(bel[q[i].l]!=bel[q[i-1].l]){d.reset();l=br[bel[q[i].l]]+1;r=l-1;ret=sqs;}if(bel[q[i].l]==bel[q[i].r]){ll res=sqs;for(ll j=q[i].l;j<=q[i].r;j++)d2.join(b[j].u,b[j].v,res,1);ans[q[i].id]=((res-sqs)%mod+mod)%mod;for(ll j=q[i].l;j<=q[i].r;j++)d2.cancel();}else {while(r<q[i].r)add_r(++r,ret);ll tret=ret,tl=l;while(l>q[i].l)add_l(--l,ret);ans[q[i].id]=((ret-sqs)%mod+mod)%mod;//我是这样计算答案的ret=tret;while(l<tl)del_l(l++);}}for(ll i=1;i<=m;i++)printf("%lld\n",ans[i]*inv%mod);return 0;
}
温馨提示,本代码思路正确,却只能通过洛谷 25 p t s \rm 25pts 25pts 的数据。
相关文章:
(回滚莫队)洛谷 P10268 符卡对决 题解
居然还没调出来?感觉是数据类型的问题,真是吓人。先把思路写一下吧。 题意 灵梦一共有 n n n 张符卡,每张卡都有一个能力值,对于第 i i i 张卡,它的能力值为 a i a_i ai,现在她想从中选出两张符卡并…...
在MacOS 10.15上使用MongoDB
这次是在MacOS 10.15上使用MongoDB。先在豆包问支持MacOS 10.15的MongoDB最新版是什么,答案是MongoDB 5.0。 抱着谨慎怀疑的态度去官方网站查询了一下,答案如下 MongoDB 7.x支持的最低版本MacOS是11MongoDB 6.x支持的最低版本MacOS是10.14 又找deepsee…...
思二勋:未来所有的业务都将生于AI、长于AI、成于AI
每个时代都有其标志性的技术,每个技术的产生或极大地解放了个体的劳动力,提高了个体与组织之间的协作效率,或极大地促进了生产效率或使用体验,或将极大地优化了资源配置和供需匹配效率,从而提高人们的生活水平。从青铜…...
混合专家模型(MoE):助力大模型实现高效计算
引言 近年来,大模型的参数规模不断攀升,如何在保证性能的前提下降低计算成本和显存消耗,成为业界关注的重点问题。混合专家模型(Mixture of Experts, MoE)应运而生,通过“分而治之”的设计理念,…...
【学习笔记】计算机网络(七)—— 网络安全
第7章 网络安全 文章目录 第7章 网络安全7.1 网络安全问题概述7.1.1 计算机网络面临的安全性威胁7.1.2 安全的计算机网络7.1.3 数据加密模型 7.2 两类密码体制7.2.1 对称密钥密码体制7.2.2 公钥密码体制 7.3 鉴别7.3.1 报文鉴别7.3.2 实体鉴别 7.4 密钥分配7.4.1 对称密钥的分配…...
预测分析(四):面向预测分析的神经网络简介
文章目录 面向预测分析的神经网络简介神经网络模型1. 基本概念2. 前馈神经网络3. 常见激活函数4. 循环神经网络(RNN)5. 卷积神经网络(CNN) MPL结构工作原理激活函数训练方法 基于神经网络的回归——以钻石为例构建预测钻石价格的M…...
Debezium日常分享系列之:Debezium 3.1.0.Final发布
Debezium日常分享系列之:Debezium 3.1.0.Final发布 重大改变Debezium Core事件源块现在带有版本号稀疏向量逻辑类型重命名更改了模式历史配置的默认值 Debezium Storage moduleJDBC 存储配置命名约定变更 Debezium for Oracle多个 Oracle LogMiner JMX 指标被移除重…...
LLaMA-Factory大模型微调全流程指南
该文档为LLaMA-Factory大模型微调提供了完整的技术指导,涵盖了从环境搭建到模型训练、推理和合并模型的全流程,适用于需要进行大模型预训练和微调的技术人员。 一、docker 容器服务 请参考如下资料制作 docker 容器服务,其中,挂…...
为什么芯片半导体行业需要全星APQP系统?--行业研发项目管理软件系统
为什么芯片半导体行业需要全星APQP系统?--行业研发项目管理软件系统 在芯片半导体行业,严格的合规性要求、复杂的供应链协同及高精度质量管理是核心挑战。全星研发项目管理APQP系统专为高门槛制造业设计,深度融合APQP五大阶段(从设…...
Linux make 检查依赖文件更新的原理
1. 文件的时间戳 make 主要依靠文件的时间戳来判断依赖文件是否有更新。每个文件在文件系统中都有一个时间戳,记录了文件的三种重要时间: 访问时间(Accesstime):文件最后一次被访问的时间。修改时间&…...
vulkanscenegraph显示倾斜模型(5.6)-vsg::RenderGraph的创建
前言 上一章深入分析了vsg::CommandGraph的创建过程及其通过子场景遍历实现Vulkan命令录制的机制。本章将在该基础上,进一步探讨Vulkan命令录制中的核心封装——vsg::RenderGraph。作为渲染流程的关键组件,RenderGraph封装了vkCmdBeginRenderPass和vkCmd…...
解锁 Python 多线程的潜力:全局解释器锁(GIL)深度解析与优化之道
解锁 Python 多线程的潜力:全局解释器锁(GIL)深度解析与优化之道 引言 Python,这门以简洁和优雅著称的编程语言,自诞生以来在 Web 开发、数据分析、人工智能等领域大放异彩。然而,Python 的多线程性能却常被诟病,其核心原因之一便是全局解释器锁(Global Interpreter …...
基于阿里云可观测产品构建企业级告警体系的通用路径与最佳实践
前言 1.1 日常生活中的告警 任何连续稳定运行的生产系统都离不开有效的监控与报警机制。通过监控,我们可以实时掌握系统和业务的运行状态;而报警则帮助我们及时发现并响应监控指标及业务中的异常情况。 在日常生活中,我们也经常遇到各种各样…...
二叉树的ACM板子(自用)
package 二叉树的中序遍历;import java.util.*;// 定义二叉树节点 class TreeNode {int val; // 节点值TreeNode left; // 左子节点TreeNode right; // 右子节点// 构造函数TreeNode(int x) {val x;} }public class DMain {// 构建二叉树(层序遍历方式&…...
架构思维:查询分离 - 表数据量大查询缓慢的优化方案
文章目录 Pre引言案例何谓查询分离?何种场景下使用查询分离?查询分离实现思路1. 如何触发查询分离?方式一: 修改业务代码:在写入常规数据后,同步建立查询数据。方式二:修改业务代码:…...
Qt进阶开发:QFileSystemModel的使用
文章目录 一、QFileSystemModel的基本介绍二、QFileSystemModel的基本使用2.1 在 QTreeView 中使用2.2 在 QListView 中使用2.3 在 QTableView 中使用 三、QFileSystemModel的常用API3.1 设置根目录3.2 过滤文件3.2.1 仅显示文件3.2.2 只显示特定后缀的文件3.2.3 只显示目录 四…...
后端开发常见的面试问题
目录 编程语言 python Linux环境 web框架 数据处理与分析 数据库 图数据库 什么是图数据库?它与传统关系型数据库有什么区别? 图数据库中的节点、边和属性分别代表什么? 常见的图数据库有哪些?它们各自有什么特点&#…...
List结构之非实时榜单实战
像京东、淘宝等电商系统一般都会有热销的商品榜单,比如热销手机榜单,热销电脑榜单,这些都是非实时的榜单。为什么是非实时的呢?因为完全实时的计算和排序对于资源消耗较大,尤其是当涉及大量交易数据时。 一般来说&…...
【C语言】字符串处理函数:strtok和strerror
在C语言中,字符串处理是编程的基础之一。本文将详细讲解两个重要的字符串处理函数:strtok和strerror 一、strtok函数 strtok函数用于将字符串分割成多个子串,这些子串由指定的分隔符分隔。其原型定义如下: char *strtok(char *s…...
如何提升后端开发效率:从Spring Boot到微服务架构
在现代软件开发中,后端开发的效率直接决定了项目的成败。随着技术的快速发展,Spring Boot、微服务架构、Docker等工具和技术已经成为提升后端开发效率的核心利器。在这篇文章中,我们将探讨如何通过使用Spring Boot及微服务架构来提升开发效率…...
go语言:开发一个最简单的用户登录界面
1.用deepseek生成前端页面: 1.提问:请你用html帮我设计一个用户登录页面,要求特效采用科技感的背景渲染加粒子流动,用css、div、span标签,并给出最终合并后的代码。 生成的完整代码如下: <!DOCTYPE h…...
基于 .NET 8 + Lucene.Net + 结巴分词实现全文检索与匹配度打分实战指南
文章目录 前言一、技术选型与优势1.1 技术栈介绍1.2 方案优势 二、环境搭建与配置2.1 安装 NuGet 包2.2 初始化核心组件 三、索引创建与文档管理3.1 构建索引3.2 动态更新策略 四、搜索与匹配度排序4.1 执行搜索4.2 自定义评分算法(扩展) 五、高级优化技…...
Docker安装、配置Nacos
1.如果没有docker-compose.yml文件的话,先创建docker-compose.yml 配置文件一般长这个样子 version: 3services:nacos:image: nacos/nacos-server:v2.1.1container_name: nacos2ports:- "8848:8848"- "9848:9848"environment:- MODEstandalone…...
《Maven高级应用:继承聚合设计与私服Nexus实战指南》
一、 Maven的继承和聚合 1.什么是继承 Maven 的依赖传递机制可以一定程度上简化 POM 的配置,但这仅限于存在依赖关系的项目或模块中。当一个项目的多个模块都依赖于相同 jar 包的相同版本,且这些模块之间不存在依赖关系,这就导致同一个依赖…...
重要头文件下的函数
1、<cctype> #include<cctype>加入这个头文件就可以调用以下函数: 1、isalpha(x) 判断x是否为字母 isalpha 2、isdigit(x) 判断x是否为数字 isdigit 3、islower(x) 判断x是否为小写字母 islower 4、isupper(x) 判断x是否为大写字母 isupper 5、isa…...
C语言数字分隔题目
一、题目引入 编写一个程序,打印出从用户输入的数字开始,递减到1的序列。要求每次打印一行,数字之间用逗号分隔,最后一个数字后面没有逗号。 二、代码展示 三、运行结果 四、思路分析 1.先用一个for循环对输入的数字进行递减 2.再对for循环里面的数字进行筛选 如果大于1 …...
DigitalOcean 发布 AMD Instinct MI300X GPU 裸金属服务器
DigitalOcean 宣布现已提供 AMD Instinct MI300X GPU,并搭载 ROCm 软件,以支持用户的 AI 任务。 在 DigitalOcean,我们致力于为你的项目提供更多选择。AMD Instinct MI300X 是目前带宽最高的 GPU 之一(5.3 TB/s 的 HBM3 内存带宽&…...
CentOS 7 镜像源失效解决方案(2025年)
执行 yum update 报错: yum install -y yum-utils \ > device-mapper-persistent-data \ > lvm2 --skip-broken 已加载插件:fastestmirror, langpacks Loading mirror speeds from cached hostfile Could not retrieve mirrorlist http://mirror…...
应对高并发的根本挑战:思维转变【大模型总结】
以下是对这篇技术总结的详细解析,以分步说明的形式呈现,帮助理解亿万并发场景下的核心策略与创新思维: 一、应对高并发的根本挑战:思维转变 1. 传统架构的局限 问题:传统系统追求零故障和强一致性,但在海…...
ARM-外部中断,ADC模数转换器
根据您提供的图片,我们可以看到一个S3C2440微控制器的中断处理流程图。这个流程图展示了从中断请求源到CPU的整个中断处理过程。以下是流程图中各个部分与您提供的寄存器之间的关系: 请求源(带sub寄存器): 这些是具体的…...
