当前位置: 首页 > news >正文

P6477 [NOI Online #2 提高组] 子序列问题 题解

原题链接

看到形如 $\sum_{l=1}^{n} \sum_{r=l}^n $ 两个 \(sum\) 叠加的形式,考虑枚举单独一维来统计一个端点固定的子序列贡献。

尝试枚举右端点,记 \(g(r) = \sum_{l=1}^{r} f(l,r)^2\) ,此时我们需要知道如何从 \(g(r)\) 转移到 \(g(r+1)\) 才能在枚举右端点时通过某种方式维护 \(g\) 的贡献。
对于区间颜色个数,加入一个新的右端点 \(r+1\),会对以 \(l \in [pre_r+1,r+1]\) 为左端点的区间的 \(f\) 函数值加一,其中 \(pre_r\) 表示 \(a_r\) 上一次出现的位置。
区间加和区间求和的操作考虑线段树维护,因为题意要求的是平方和,每次区间加对平方和的影响可以用完全平方公式拆解(byd代码里把式子写错了调了100年)

\[\begin{align} ( (a_1+v)^2+(a_2+v)^2+(a_3+v)^2+(a_4+v)^2) \newline =(a_1^2+a_2^2+a_3^2+a_4^2)+2v(a_1+a_2+a_3+a_4)+4v^2\end{align} \]

所以总的操作就是枚举右端点,每次对 \([pre_r+1,r]\) 区间加 \(1\),线段树里维护区间和,区间平方和,对于每个右端点都查询一次 \([1,r]\) 的平方和即可。

\(1e6\) 级别的 \(n\) 线段树容易被卡常,不过当然不包括 \(zkw\) 线段树
时间复杂度 \(O(n \log n)\)

点击查看代码
using namespace std;
const int N=1e6+5;
const int mod=1e9+7;
int pre[N],tmp[N],a[N],lsh[N],tot;
int sum1[N<<2],sum2[N<<2],tag[N<<2],P=1,DEP;
int ans,n;
ili void add(int &x,int y){x+=y;if(x>=mod) x-=mod;}
ili void pa(int i,int len,int v){add(sum2[i],2*sum1[i]*v%mod+len*v*v%mod);add(sum1[i],len*v);tag[i]+=v;
}
ili void pushdown(int i,int siz){siz>>=1;if(tag[i]){pa(ls(i),siz,tag[i]);pa(rs(i),siz,tag[i]);tag[i]=0;}
}
ili void update(int l,int r){l+=P-1,r+=P+1;int siz=1;for(int i=DEP;i;i--) pushdown(l>>i,1<<i),pushdown(r>>i,1<<i);while(l^1^r){if(~l&1) pa(l^1,siz,1);if(r&1)  pa(r^1,siz,1);l>>=1,r>>=1,siz<<=1;sum1[l]=(sum1[ls(l)]+sum1[rs(l)])%mod,sum2[l]=(sum2[ls(l)]+sum2[rs(l)])%mod;sum1[r]=(sum1[ls(r)]+sum1[rs(r)])%mod,sum2[r]=(sum2[ls(r)]+sum2[rs(r)])%mod;}for(l>>=1;l;l>>=1) sum1[l]=(sum1[ls(l)]+sum1[rs(l)])%mod,sum2[l]=(sum2[ls(l)]+sum2[rs(l)])%mod;
}
ili int query(int l,int r){l+=P-1,r+=P+1;int res=0;for(int i=DEP;i;i--) pushdown(l>>i,1<<i),pushdown(r>>i,1<<i);while(l^1^r){if(~l&1) add(res,sum2[l^1]);if(r&1) add(res,sum2[r^1]);l>>=1,r>>=1;}return res;
}
void xpigeon(){rd(n);for(int i=1;i<=n;i++){rd(a[i]);lsh[i]=a[i];}sort(lsh+1,lsh+1+n);tot=unique(lsh+1,lsh+n+1)-(lsh+1);for(int i=1;i<=n;i++){a[i]=lower_bound(lsh+1,lsh+tot+1,a[i])-lsh;pre[i]=tmp[a[i]];tmp[a[i]]=i;}while(P<=n+1) P<<=1,DEP++;for(int r=1;r<=n;r++){update(pre[r]+1,r);add(ans,query(1,n));}cout<<ans%mod<<'\n';
}
http://www.hskmm.com/?act=detail&tid=178

相关文章:

  • iframe 跨域通信实战:可视化编辑器的技术实现
  • windows项目下统计代码行数
  • 。。。
  • ETF 简介
  • 实时流式响应的 SSE 技术实现
  • 2025年艺术、教育和管理国际学术会议(ICAEM 2025)- 第五期
  • CF 1048 Div.2 解题报告
  • reLeetCode 热题 100-1 两数之和-扩展1 unordered_map实现 - MKT
  • 读书笔记:什么是对象表?
  • AI 服务路由策略:如何实现智能负载均衡
  • 在SQL语句中的别名
  • 多维度排序算法在企业级应用中的性能优化
  • 正则表达式在代码解析中的高级应用
  • vue3 项目中优雅的使用 SVG 图标(vite-plugin-svg-icons)
  • 自我介绍+软工5问
  • 车道线检测资料
  • 实现Jenkins不同账号只能看到各自任务的权限
  • 6 个最佳无代码 IT 资产管理工具推荐
  • python开发mcp入门
  • 建造者模式进阶:复杂AI服务的优雅构建
  • 代理模式在AI应用中的安全实践:AOP + 限流 + 权限控制
  • ​​高压差分探头:高电压测量的精密之眼​​
  • OCP认证烂大街了吗?别跟风问这个问题了
  • 全国连锁贸易公司数字化管理软件-优德普SAP零售行业解决方案
  • Win7、WinServer2008运行.net8.net4.8程序的解决方案
  • 虚机网络配置基础 - 小
  • 你的开发服务器在说谎-热重载与热重启的关键区别
  • 文件不只是数据-一份稳健的文件处理指南
  • 别再猜了-开始测量吧-一份实用的Web性能指南
  • 软工作业1