zoukankan      html  css  js  c++  java
  • Codeforces 1209E2. Rotate Columns (hard version)

    传送门

    发现 $n$ 很小,考虑状压 $dp$,但是如果强行枚举列并枚举置换再转移复杂度太高了

    考虑推推结论,发现我们只要保留列最大值最大的 $n$ 列即可,证明好像挺显然:

    假设我们让列最大值比较小的列贡献给某一行,那么由抽屉原理发现这意味着列最大值排名前 $n$ 的某一列一定没对答案贡献,

    此时我们完全可以用那一列的最大值替换原本这一列对答案的贡献,这种情况同样可以推广到列最大值比较小的列贡献给多行的情况

    所以证明就完成了

    保留完最大的 $n$ 列,然后直接暴力 $dp$,设 $f[i][S]$ 表示考虑完前 $i$ 列,确定了的行的集合为 $S$ 时的最大值

    那么转移就枚举子集,比子集多出来确定的行即为第 $i$ 列对答案贡献的行

    增加的贡献设为 $mx[i][S]$ 表示第 $i$ 列,贡献的集合为 $S$ 时的最大值,这个可以枚举置换 $2^n cdot n^2$ 预处理

    然后枚举子集进行 $dp$ 的复杂度为 $3^n cdot n$ ,总复杂度算一下达到了 $1e8$ 的级别

    但是 $CF$ 评测机比较快并且这题时间限制比较充裕,稳得要死.jpg

    多组数据注意要清空

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=13,M=2007;
    int T,n,m,mx[N][1<<N],f[N][1<<N];
    struct dat {
        int a[N],b[N];
        inline bool operator < (const dat &tmp) const {
            for(int i=n-1;i>=0;i--)
                if(b[i]!=tmp.b[i]) return b[i]<tmp.b[i];
            return 0;
        }
    }d[M];
    int main()
    {
        T=read();
        while(T--)
        {
            n=read(),m=read();
            for(int i=0;i<n;i++)
                for(int j=0;j<m;j++) d[j].a[i]=d[j].b[i]=read();
            for(int i=0;i<m;i++) sort(d[i].b,d[i].b+n);
            sort(d,d+m); reverse(d,d+m); int Mx=(1<<n)-1;
            for(int i=0;i<n;i++)
                for(int j=1;j<=Mx;j++) mx[i][j]=0;
            for(int i=0;i<n;i++)
                for(int j=0;j<n;j++)
                    for(int k=1;k<=Mx;k++)
                    {
                        int t=0;
                        for(int l=0;l<n;l++)
                            if((k>>l)&1) t+=d[i].a[(j+l)%n];
                        mx[i][k]=max(mx[i][k],t);
                    }
            for(int i=0;i<n;i++)
                for(int j=0;j<=Mx;j++) f[i][j]=(i==0 ? mx[i][j] : 0);
            for(int i=1;i<n;i++)
                for(int o=0;o<=Mx;o++)
                {
                    f[i][o]=mx[i][o];
                    for(int p=o;p;p=(p-1)&o)
                        f[i][o]=max(f[i][o],f[i-1][p]+mx[i][o^p]);
                }
            printf("%d
    ",f[n-1][Mx]);
            for(int i=0;i<m;i++)
                for(int j=0;j<n;j++) d[i].a[j]=d[i].b[j]=0;//这里要记得清空啊
        }
        return 0;
    }
  • 相关阅读:
    linux定时任务之crontab
    Examples of GoF Design Patterns--摘录
    weblogic升级之ddconverter
    Memcached分布式算法详解--转
    java实现迷宫算法--转
    kmp java implement--转
    2013年小结及2014年展望
    深入redis内部--字典实现
    项目管理学习笔记之二.工作分解
    android在当前app该文件下创建一个文件夹
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11526520.html
Copyright © 2011-2022 走看看