当前位置: 首页 > 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.zskr.cn/news/1019.html

相关文章:

  • 。。。
  • CF 1048 Div.2 解题报告
  • AI 服务路由策略:如何实现智能负载均衡
  • 多维度排序算法在企业级应用中的性能优化
  • 正则表达式在代码解析中的高级应用
  • 实现Jenkins不同账号只能看到各自任务的权限
  • 6 个最佳无代码 IT 资产管理工具推荐
  • python开发mcp入门
  • OCP认证烂大街了吗?别跟风问这个问题了
  • 虚机网络配置基础 - 小
  • 移动端盒子元素实现左右可滑动且竖向页面可滑动
  • 双桶倒水的Python程序
  • 微信小程序触发订阅消息
  • MySQL锁
  • AI智能体(Agent)开发实战:工业级项目案例驱动课
  • java 开发中VO、PO、DO、DTO、BO、QO、DAO、POJO
  • JDK 24软件介绍
  • 数据跨境学习笔记
  • NOIP 模拟赛十三
  • 目录导航
  • archlinux gnome48 顶部托盘选择
  • 第8章 STM32CUBE LCD配置和测试
  • Git的使用方法
  • 微算法科技(NASDAQ: MLGO)采用量子相位估计(QPE)方法,增强量子神经网络训练
  • DeepSeek文案短句:点燃创意火花
  • 如何通过Python SDK 统计Collection
  • 小程序web-view全覆盖问题
  • MySQL触发器
  • nvm下载与安装(Windows)
  • OSI 七层协议 和四层协议