zoukankan      html  css  js  c++  java
  • 高维前缀和(sosdp) & AT4168 [ARC100C] Or Plus Max

    洛谷传送门


    高维前缀和

    一维二维前缀和
    首先多维前缀和肯定可以像二维一样进行容斥求出,但是很显然复杂度爆炸。
    所以我们使用另一种求法。
    二维前缀和:

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

    可以理解为先对于每一列求关于行的前缀和,再在每一行加起来。
    三维前缀和:

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

    这样n维的前缀和时间复杂度就降到了 (O(na^n))

    应用--子集

    例如

    对于所有的 (i(0≤i≤2n−1)),求解 (sum_{j⊂i}a_j)

    令 dp[i][j] 表示考虑数 j 二进制的后 i 位的子集和。
    于是就有了代码:

    for(int i=1;i<=n;i++){
    	for(int j=0;j<(1<<n);j++){
    		if(j&(1<<(i-1))) dp[i][j]+=dp[i-1][j^(1<<(i-1))];
    		else dp[i][j]=dp[i-1][j];
    	}
    }
    

    但是一般用滚动数组优化一下,于是就有:

    for(int i=0,i<n;i++){
    	for(int j=0;j<(1<<n);j++){
    		if(j&(1<<i)) dp[j]+=dp[j^(1<<i)];
    	}
    }
    

    解题思路

    可以用求子集的方法来解此题。
    用d[i][0/1]表示i的子集中的最大值/次大值。
    注意最后因为题目要求是<=k,所以要取max。

    AC代码

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<ctime>
    using namespace std;
    const int maxn=3e5;
    int nn,n,a[maxn],d[maxn][2],ans;
    void add(int a,int b){
    	if(d[a][0]<d[b][0]){
    		d[a][1]=max(d[a][0],d[b][1]);
    		d[a][0]=d[b][0];
    	}
    	else if(d[a][1]<d[b][0]) d[a][1]=d[b][0];
    }
    int main(){
    	ios::sync_with_stdio(false);
    	cin>>nn;
    	n=1<<nn;
    	for(int i=0;i<n;i++) cin>>d[i][0];
    	for(int i=0;i<nn;i++){
    		for(int j=0;j<n;j++){
    			if(j&(1<<i)) add(j,j^(1<<i));
    		}
    	}
    	for(int i=1;i<n;i++){
    		ans=max(ans,d[i][0]+d[i][1]);
    		cout<<ans<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    tshark的命令使用
    svn log查看自己提交的记录
    账号安全 syyh
    Trivy 容器镜像扫描工具学习 syyh
    《关键对话》脑图整理 syyh
    Grafana 任意文件读取漏洞 (CVE202143798)学习 syyh
    容器安全管理 syyh
    【Sass/SCSS】我花4小时整理了的Sass的函数
    【JavaScript使用技巧】三个截取字符串中的子串,你用的哪个
    【SVG】为了前端页面的美丽,我选择学习SVG
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/15036070.html
Copyright © 2011-2022 走看看