高维前缀和

高维前缀和高维前缀和就是求关于一个集合子集 或超集 的状态的和牛客有一道题写的很好传送门题面就已经说明了高维前缀和的原理链接 https ac nowcoder com acm contest 167 C 来源 牛客网对于一个一维数组求部分和 可以使用如下代码 for inti 1 i lt n i a i a i 1 对于一个二维数组

高维前缀和就是求关于一个集合子集(或超集)的状态的和

对于一个一维数组求部分和,可以使用如下代码

for (int i = 1; i <= n; i++) { 
    a[i] += a[i - 1]; } 

对于一个二维数组求部分和,可以使用如下代码

for (int i = 1; i <= n; i++) { 
    for (int j = 1; j <= n; j++) { 
    a[i][j] += a[i - 1][j] + a[i][j - 1] - a[i - 1][j - 1]; } } 

或如下代码

for (int i = 1; i <= n; i++) { 
    for (int j = 1; j <= n; j++) { 
    a[i][j] += a[i][j - 1] } } for (int i = 1; i <= n; i++) { 
    for (int j = 1; j <= n; j++) { 
    a[i][j] += a[i - 1][j] } } 

第二份代码看起来更麻烦更慢,来考虑一下三维的情况。

for (int i = 1; i <= n; i++) { 
    for (int j = 1; j <= n; j++) { 
    for (int k = 1; k <= n; k++) { 
    a[i][j][k] += a[i][j][k - 1] + a[i][j - 1][k] + a[i - 1][j][k]; a[i][j][k] -= a[i][j - 1][k - 1] + a[i - 1][j - 1][k] + a[i - 1][j][k - 1]; a[i][j][k] += a[i - 1][j - 1][k - 1]; } } } 

或如下代码

for (int i = 1; i <= n; i++) { 
    for (int j = 1; j <= n; j++) { 
    for (int k = 1; k <= n; k++) { 
    a[i][j][k] += a[i][j][k - 1]; } } } for (int i = 1; i <= n; i++) { 
    for (int j = 1; j <= n; j++) { 
    for (int k = 1; k <= n; k++) { 
    a[i][j][k] += a[i][j - 1][k]; } } } for (int i = 1; i <= n; i++) { 
    for (int j = 1; j <= n; j++) { 
    for (int k = 1; k <= n; k++) { 
    a[i][j][k] += a[i - 1][j][k]; } } } 

第二份代码就不一定更慢了(第二份复杂度大约3n3,第一份复杂度大概8n3)
随着维度更高,第一份代码容斥时项数越来越多,而第二份只是多一次遍历整个数组,优势越来越大。
同样的思路能不能推广到更高维的情况呢?




最后的解决方法就是高维前缀和,从低到高枚举位数,然后枚举从 0 0 0 n − 1 n-1 n1的所有元素
核心代码如下:

for(int i=0;(1<<i)<n;i++) for(int j=0;j<n;j++) if(j&(1<<i)) a[j]+=a[j^(1<<i)]; 

复杂度 O ( n × 2 n ) O(n\times 2^n) O(n×2n)
完整代码:

#include 
     #include 
     #include 
     #include 
     #include 
     using namespace std; inline int rd(){ 
    int x=0,f=1;char c=' '; while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar(); while(c<='9' && c>='0') x=x*10+c-'0',c=getchar(); return x*f; } const int maxn=(1<<20)+5; int n,a[maxn],sum[maxn]; int main(){ 
    n=rd(); for(int i=0;i<n;i++) a[i]=rd(); for(int i=0;(1<<i)<n;i++) for(int j=0;j<n;j++) if(j&(1<<i)) a[j]+=a[j^(1<<i)]; for(int i=0;i<n;i++) printf("%d\n",a[i]); return 0; } 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/215865.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午12:59
下一篇 2026年3月18日 下午12:59


相关推荐

  • 多模态学习「建议收藏」

    多模态学习「建议收藏」作者:张致远#mermaid-svg-bqinfdlcry278edQ.label{font-family:’trebuchetms’,verdana,arial;font-family:var(–mermaid-font-family);fill:#333;color:#333}#mermaid-svg-bqinfdlcry278edQ.labeltext{fill:#333}#mermaid-svg-bqinfdlcry278edQ.noderect,#mermaid-svg-..

    2022年6月29日
    38
  • FC游戏 《三国志2-霸王的大陆》攻略「建议收藏」

    FC游戏 《三国志2-霸王的大陆》攻略「建议收藏」《三国志2-霸王的大陆》是日本南梦宫公司研发的一款历史战略模拟游戏,于1992年06月10日在红白机平台上发行。在开始游戏选择君主时(一定要在君主未出现前的画面时进行第二步),按住1P的START不要放,按住START同时,连续依次按上,下,左,右,按满3次,听到“乒”一下的声音后再开始游戏,这时再选君主:君主城金钱、兵马、宝等全满。一、武将1)武将出场时间189年-190…

    2025年8月19日
    4
  • 开源阅读书源_阅读3.20.0518追书神器 海量书源 免费开源无广告[通俗易懂]

    开源阅读书源_阅读3.20.0518追书神器 海量书源 免费开源无广告[通俗易懂]特别声明所有软件皆来源于网上收集整理,仅供学习与交流技术,不得用作其它用途,如有侵犯你的权益,请联系我们,我们将于24小时内进行删除,谢谢你的配合!1阅读是一款开源免费的无人维护的电子书阅读应用程序。作者感言:如今的电子小说阅读应用总是在不断的添加广告,作为一个程序猿这是受不了的,于是开源的阅读软件来,你不用再担心广告。本软件fork一个无人维护的阅读软件,经过大量修改,实现自定义书源,…

    2022年6月21日
    1.8K
  • 如何一键远程开机,远程唤醒功能[通俗易懂]

    如何一键远程开机,远程唤醒功能[通俗易懂]使用ToDesk可以在千里之外为您的设备远程进行开机操作视频教程:https://update.todesk.com/wol.mp4ToDesk支持将关机状态下的设备(Windows,macOS,Linux)唤醒开机.这需要满足2个条件:1.开启电脑的网卡WakeOnLAN功能2.您要开机的电脑设备在同一交换机(路由器下),需要有另外一个ToDesk端在运行.比如其他的电脑或手机,iPad,Android电视盒子,或家人的手机安装一个ToDesk,这样您就可以在千里之外为您的电脑

    2022年6月2日
    85
  • mysqltext长度需要设置嘛_text字段类型需要设置大小吗

    mysqltext长度需要设置嘛_text字段类型需要设置大小吗受到@Ankan-Zerob的挑战,这是我对可以存储在以字为单位的每种文本类型中的最大长度的估计:Type|Bytes|Englishwords|Multi-bytewords———–+—————+—————+—————–TINYTEXT|255|…

    2022年8月13日
    13
  • Python中range()函数的使用方法

    Python中range()函数的使用方法range 函数可以产生一系列的数字 当需要叠加一些数字时 可以用到 range 函数 1 基本语法 range 函数的基本语法如下所示 range start stop 其中 start 表示这一些列数字中的第一个数字 stop 1 表示这一系列数字中的最后一个数字 需要注意的是 产生的数字中不包括 stop 2 使用方法 range 函数产生的这一系列的数字并不是以列表 list 类型存在的 这样做的目的是为了节省代码所占空间 2 1 将 range 产生的数字转换为列表

    2026年3月18日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号