codeforces#1290E2 - Rotate Columns (hard version)(子集dp)

Posted carcar

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了codeforces#1290E2 - Rotate Columns (hard version)(子集dp)相关的知识,希望对你有一定的参考价值。

题目链接:

https://codeforces.com/contest/1209/problem/E2

题意:

给出$n$行和$m$列

每次操作循环挪动某列一次

可以执行无数次这样的操作

让每行最大值的累加和最大

数据范围:

$1\leq n \leq 12$

$1\leq m \leq 20000$

分析: 

定义$dp[i][j]$,考虑前$i$列,选择状态为$j$的最大值

$ans=dp[m][(1<<n)-1]$

$dp[i][j]$可以由$dp[i-1][k]$转移,$k$是$j$的二进制子集

$easy$难度还是比较好写的

$hard$难度需要预处理,和保留最多$n$列

ac代码:

#include<bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
using namespace std;
const int maxn=12+10;
const int maxm=2007;
int num[maxn][maxm];
pii p[maxn*maxm];
int lis[maxn][maxn],cnt;
int dp[maxn][(1<<12)+10],f[maxn][(1<<12)+10];
set<int>se;
int main()

    int T;
    scanf("%d",&T);
    while(T--)
        int n,m;
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                scanf("%d",&num[i][j]);
                p[(i-1)*m+j]=make_pair(num[i][j],j);
            
        
         sort(p+1,p+1+n*m);
         se.clear();
         for(int i=0;i<n*m;i++)
             se.insert(p[n*m-i].second);
             if(se.size()==n)break;//保留最多n列
         
         int cnt=0;
         for(auto i:se)
             cnt++;
             for(int j=1;j<=n;j++)
                 lis[j][cnt]=num[j][i];
         
         m=cnt;

        int len=(1<<n);
        memset(f,0,sizeof(f));
        for(int i=1;i<=m;i++)//预处理每列选择状态的最优解
            for(int choose=0;choose<len;choose++)

                for(int j=1;j<=n;j++)
                     int res=0;
                    for(int k=1;k<=n;k++)
                        int g=(k-1+j)%n+1;
                        if((1<<(g-1))&choose)res+=lis[k][i];
                    
                    f[i][choose]=max(res,f[i][choose]);
                

        
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=m;i++)
            for(int choose=0;choose<len;choose++)
                for(int shift=choose;;shift=((shift-1)&choose))//枚举choose的子集
                    int v=choose-(shift&choose);
                    dp[i][choose]=max(dp[i][choose],dp[i-1][shift]+f[i][v]);
                    if(shift==0)break;
                
            
        
        printf("%d\n",dp[m][len-1]);
    
    return 0;

  

以上是关于codeforces#1290E2 - Rotate Columns (hard version)(子集dp)的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces 1290B/1291D - Irreducible Anagrams

codeforces 391E2 (Codeforces Rockethon 2014E2)

CodeForces - 1251E2 (思维+贪心)

codeforces#1251E2. Voting (Hard Version)(贪心)

CodeForces -Codeforces Round #496 (Div. 3) E2. Median on Segments (General Case Edition)

Codeforces 1108E2 Array and Segments (Hard version) 差分, 暴力