zoukankan      html  css  js  c++  java
  • [cf1209E]Rotate Columns

    题意也可以理解为这样一个过程:

    对于每一列,将其旋转后选出若干行上的数,要求与之前的行都不同

    用$g_{i,S}$表示第$i$列选出的行数集合为$S$的最大和,$f_{i,S}$表示前$i$列$S$中的行已经选择的最大和,转移通过枚举子集,复杂度为$o(Qm3^{n})$

    关于$g_{i,S}$的计算可以先预处理$sum_{i,S}$表示第$i$列$S$这些行的和(不旋转),接下来枚举旋转,用二进制简单维护,复杂度为$o(Qnm2^{n})$

    (代码中利用的是找到其最小表示法,并直接从最小表示法处转移,如果定义轮换相同,则本质不同的串根据polya定理大约为$o(frac{2^{n}}{n})$,暴力$o(n^{2})$统计复杂度相同)

    进一步的,只需要选择最大值最大的$n$列(相同任取)即可,如果在另外一列选择,那么这$n$列中一定有一个列被选择,同时那一列中可以任意旋转,用该列最大值来替换这“另外一列”一定不劣

    最终时间复杂度为$o(Qn3^{n}+Qn^{2}2^{n})$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 12
     4 #define M 2005
     5 int t,n,m,a[M][N],mx[1<<N],f[N+5][1<<N];
     6 pair<int,int>b[M];
     7 int main(){
     8     scanf("%d",&t);
     9     while (t--){
    10         scanf("%d%d",&n,&m);
    11         for(int i=0;i<n;i++)
    12             for(int j=1;j<=m;j++)scanf("%d",&a[j][i]);
    13         for(int i=1;i<=m;i++){
    14             b[i].first=0;
    15             for(int j=0;j<n;j++)b[i].first=max(b[i].first,a[i][j]);
    16             b[i].first*=-1;
    17             b[i].second=i;
    18         }
    19         sort(b+1,b+m+1);
    20         m=min(n,m);
    21         for(int ii=1;ii<=m;ii++){
    22             int i=b[ii].second;
    23             for(int j=0;j<(1<<n);j++){
    24                 mx[j]=0;
    25                 int s=j;
    26                 for(int k=1;k<n;k++)s=min(s,(j>>k)+((j&((1<<k)-1))<<(n-k)));
    27                 if (s==j){
    28                     for(int k=0;k<n;k++){
    29                         int s=0;
    30                         for(int l=0;l<n;l++)
    31                             if (j&(1<<l))s+=a[i][(k+l)%n];
    32                         mx[j]=max(mx[j],s);
    33                     }
    34                 }
    35                 else mx[j]=mx[s];
    36             }
    37             for(int j=0;j<(1<<n);j++){
    38                 f[ii][j]=0;
    39                 for(int k=j;;k=((k-1)&j)){
    40                     f[ii][j]=max(f[ii][j],f[ii-1][k]+mx[j^k]);
    41                     if (!k)break;
    42                 }
    43             }
    44         }
    45         printf("%d
    ",f[m][(1<<n)-1]);
    46     }
    47     return 0;
    48 }
    View Code
  • 相关阅读:
    2.2阶乘末尾0的个数,最低位1的位置
    samba服务器使用
    全排列的非递归算法
    2.1二进制数中1的个数
    2.3发帖水王
    C #与##的使用
    NEU1141the unique number
    【转】4习惯让你越休息越累
    二叉树由先序遍历和中序遍历输出后序遍历
    UVA100
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14475945.html
Copyright © 2011-2022 走看看