zoukankan      html  css  js  c++  java
  • 题解 CF1209E2 【Rotate Columns (hard version)】

    行很少,列很多。

    最终的答案只跟每一行有关,所以有些列是没用的。

    或者换个角度理解,我们按一列上的最大数将这 (m) 列排序,把第一列上的最大数放在第 1 行,第二列上的最大数房子第 2 行,……,把第 (n) 列上的最大数放在第 (n) 行。于是我们发现第 (n+1sim m) 列甚至连最大数都是没用的,况且前 (n) 列不仅会用到最大数,其它数也都有用到的可能,所以可能有用的列数只有 (min(n,m)) 条。

    接下来就考虑状压 DP,考虑状态 (f_{i,j}) 表示处理到排序后的第 (i) 列,行上的状态为 (j)(1 表示已经确定了最大数,0 表示没有确定最大数)中已经确定最大数的最大和。

    考虑转移,枚举子集,并计算子集的最大贡献,复杂度为 (O(3^nn^3)) 但这是无法接受的。

    我们发现瓶颈在于计算子集的最大贡献需要 (O(n^2)) 的复杂度,而一个子集可能会被计算多次,于是考虑提前预处理,得到复杂度为 (O(3^n n+2^nn^3))

    代码:

    #include<bits/stdc++.h>
    #define log(a) cerr<<"33[32m[DEBUG] "<<#a<<'='<<(a)<<" @ line "<<__LINE__<<"33[0m"<<endl
    #define LL long long
    #define SZ(x) ((int)x.size()-1)
    #define ms(a,b) memset(a,b,sizeof a)
    #define F(i,a,b) for(int i=(a);i<=(b);++i)
    #define DF(i,a,b) for(int i=(a);i>=(b);--i)
    using namespace std;
    inline int read(){char ch=getchar(); int w=1,c=0;
    	for(;!isdigit(ch);ch=getchar()) if (ch=='-') w=-1;
    	for(;isdigit(ch);ch=getchar()) c=(c<<1)+(c<<3)+(ch^48);
    	return w*c;
    }
    template<typename T>inline void write(T x){
        unsigned long long y=0;T l=0;
        if(x<0)x=-x,putchar(45);
        if(!x){putchar(48);return;}
        while(x){y=y*10+x%10;x/=10;l++;}
        while(l){putchar(y%10+48);y/=10;l--;}
    }
    template<typename T>inline void writeln(T x){write(x);puts("");}
    template<typename T>inline void writes(T x){write(x);putchar(32);}
    const int N=13,M=2010,K=(1<<N)+10;
    int f[N][K],a[N][M],t[K];
    struct Column{
    	int maxn,id;
    	inline bool operator<(const Column&t)const{
    		return maxn>t.maxn;
    	}
    }c[M];
    signed main(){
    	int _=read();while(_--){
    		int n=read(),m=read();
    		F(i,1,m)c[i].id=i,c[i].maxn=0;
    		F(i,1,n)
    			F(j,1,m){
    				a[i][j]=read();
    				c[j].maxn=max(c[j].maxn,a[i][j]);
    			}
    		sort(c+1,c+m+1);
    		F(i,1,min(n,m)){
    			F(j,0,(1<<n)-1){
    				t[j]=0;
    				F(k,0,n-1){
    					int sum=0;
    					F(l,0,n-1)
    						if((j>>l)&1)sum+=a[(l+k)%n+1][c[i].id];
    					t[j]=max(t[j],sum);
    				}
    			}
    			F(j,0,(1<<n)-1){
    				f[i][j]=f[i-1][j];
    				for(int k=j;k;k=(k-1)&j)
    					f[i][j]=max(f[i][j],f[i-1][j^k]+t[k]);
    			}
    		}writeln(f[min(n,m)][(1<<n)-1]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    shell面试题整理
    用循环链表实现Josephus问题
    in与exists的区别
    单链表的建立/测长/打印/删除/排序/逆序/寻找中间值
    float在内存中的存放
    crontab定时任务详解
    螺旋队列问题之二
    螺旋队列问题之一
    android网络编程--从网络下载图片,并保存到内存卡
    android Shader类简介_渲染图像示例
  • 原文地址:https://www.cnblogs.com/zhaohaikun/p/15139249.html
Copyright © 2011-2022 走看看