• 51nod2383


    2383 高维部分和

     

    输入一个长度为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=0;
        bool f=0;
        char ch=' ';
        while(!isdigit(ch))
        {
            f|=(ch=='-'); ch=getchar();
        }
        while(isdigit(ch))
        {
            s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
        }
        return (f)?(-s):(s);
    }
    #define R(x) x=read()
    inline void write(ll x)
    {
        if(x<0)
        {
            putchar('-'); x=-x;
        }
        if(x<10)
        {
            putchar(x+'0');    return;
        }
        write(x/10);
        putchar((x%10)+'0');
        return;
    }
    #define W(x) write(x),putchar(' ')
    #define Wl(x) write(x),putchar('
    ')
    const int N=2097157;
    int n,a[N];
    int main()
    {
        freopen("std.in","r",stdin);
        freopen("std.out","w",stdout);
        int i,j;
        R(n);
        for(i=0;i<n;i++) R(a[i]);
        for(j=1;j<=n;j<<=1)
        {
            for(i=0;i<n;i++) if((i&j)==j)
            {
                a[i]+=a[i^j];
            }
        }
        for(i=0;i<n;i++) Wl(a[i]);
        return 0;
    }
    /*
    input
    8
    1
    2
    4
    8
    16
    32
    64
    128
    output
    1
    3
    5
    15
    17
    51
    85
    255
    */
    View Code
  • 相关阅读:
    WebDriverAgent入门篇-安装和使用
    5分钟了解TypeScript
    “软到不行”的WWDC2018
    IntelliJ idea 撤回(已经commit未push的)操作
    【java并发核心一】Semaphore 的使用思路
    Spring Boot 如何干掉 if else?
    到底什么是重入锁,拜托,一次搞清楚!
    mysql 递归查找菜单节点的所有子节点
    sql语句递归查询(start with)
    js实现对上传图片的路径转成base64编码,并且对图片进行压缩,实现预览功能1
  • 原文地址:https://www.cnblogs.com/gaojunonly1/p/10720804.html
Copyright © 2020-2023  润新知