2383 高维部分和

  1. 1 秒
  2. 131,072 KB
  3. 80 分
  4. 5 级题
 

输入一个长度为n的数组a[i],下标从0开始(0到n-1)
保证n是2的整数次幂,
对于每个i (0 <= i < n)
求所有满足((i & j) == j)的a[j]之和。

其中&表示按位与,即C++和C中的&,Pascal中的and。

对于100%的数据,1 <= n <= 220, 0 <= a[i] <= 1000
对于70%的数据,1 <= n <= 215,
对于50%的数据,1 <= n <= 210,

虽然这是一个简单题,但是为了降低难度,你可以看看下面的解释。

对于一个一维数组求部分和,可以使用如下代码
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];
        }
    }
}
第二份代码就不一定更慢了(第二份复杂度大约3n^3,第一份复杂度大概8n^3)
随着维度更高,第一份代码容斥时项数越来越多,而第二份只是多一次遍历整个数组,优势越来越大。
同样的思路能不能推广到更高维的情况呢?

收起

 

输入

第一行一个整数n
接下来n行n个整数,表示a[i]

输出

输出共n行,其中第i(0 <= i < n)行表示i的答案。

输入样例

8
1
2
4
8
16
32
64
128

输出样例

1
3
5
15
17
51
85
255 sol:表示只要找找规律就行了(假)
大概像是前缀和一样呗,对于每一位,加上异或那位的值就可以了,这样是不会重复的,
 
#include <bits/stdc++.h>
using namespace std;
typedef int ll;
inline ll read()
{
ll s=;
bool f=;
char ch=' ';
while(!isdigit(ch))
{
f|=(ch=='-'); ch=getchar();
}
while(isdigit(ch))
{
s=(s<<)+(s<<)+(ch^); ch=getchar();
}
return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
if(x<)
{
putchar('-'); x=-x;
}
if(x<)
{
putchar(x+''); return;
}
write(x/);
putchar((x%)+'');
return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('\n')
const int N=;
int n,a[N];
int main()
{
freopen("std.in","r",stdin);
freopen("std.out","w",stdout);
int i,j;
R(n);
for(i=;i<n;i++) R(a[i]);
for(j=;j<=n;j<<=)
{
for(i=;i<n;i++) if((i&j)==j)
{
a[i]+=a[i^j];
}
}
for(i=;i<n;i++) Wl(a[i]);
return ;
}
/*
input
8
1
2
4
8
16
32
64
128
output
1
3
5
15
17
51
85
255
*/

51nod2383的更多相关文章

随机推荐

  1. redis学习(五)——Set数据类型

    一.概述 在Redis中,我们可以将Set类型看作为没有排序的字符集合,和List类型一样,我们也可以在该类型的数据值上执行添加.删除或判断某一元素是否存在等操作.需要说明的是,这些操作的时间复杂度为 ...

  2. Java多线程(六)——线程让步

    一.yield()介绍 yield()的作用是让步.它能让当前线程由“运行状态”进入到“就绪状态”,从而让其它具有相同优先级的等待线程获取执行权:但是,并不能保证在当前线程调用yield()之后,其它 ...

  3. CF960G Bandit Blues 第一类斯特林数、NTT、分治/倍增

    传送门 弱化版:FJOI2016 建筑师 由上面一题得到我们需要求的是\(\begin{bmatrix} N - 1 \\ A + B - 2 \end{bmatrix} \times \binom ...

  4. 开启Tomcat的manager页面访问

    如何进入Tomcat的manager页面 一张图解决! 找到conf目录下的tomcat-users.xml文件,打开. <role rolename="admin-gui" ...

  5. ReactJs移动端兼容问题汇总

    汽车H5使用ReactJs问题汇总 Q:安卓4.4webview显示空白? A:初步怀疑是css属性没有加前缀引发的兼容问题,但添加后发现也不行,通过webview调试后控制台输出Set is und ...

  6. Python requests 多线程抓取 出现HTTPConnectionPool Max retires exceeded异常

    https://segmentfault.com/q/1010000000517234 -- ::, - oracle - ERROR - data format error:HTTPConnecti ...

  7. Accordion CodeForces - 1101B (实现)

    An accordion is a string (yes, in the real world accordions are musical instruments, but let's forge ...

  8. java中的代码块是什么意思,怎么用

    代码块是一种常见的代码形式.他用大括号“{}”将多行代码封装在一起,形成一个独立的代码区,这就构成了代码块.代码块的格式如下:   方法/步骤     普通代码块:是最常见的代码块,在方法里用一对“{ ...

  9. 03-命令图片.doc

  10. Linux下破解pycharm

    1.下载 https://pan.baidu.com/s/119UO4SGIEW_cxf0LmZzx3w 并将 JetbrainsCrack-3.1-release-enc.jar 放置到 pycha ...