[cf1209E]Rotate Columns

題意也能夠理解爲這樣一個過程:c++

對於每一列,將其旋轉後選出若干行上的數,要求與以前的行都不一樣ide

用$g_{i,S}$表示第$i$列選出的行數集合爲$S$的最大和,$f_{i,S}$表示前$i$列$S$中的行已經選擇的最大和,轉移經過枚舉子集,複雜度爲$o(Qm3^{n})$spa

關於$g_{i,S}$的計算能夠先預處理$sum_{i,S}$表示第$i$列$S$這些行的和(不旋轉),接下來枚舉旋轉,用二進制簡單維護,複雜度爲$o(Qnm2^{n})$it

(代碼中利用的是找到其最小表示法,並直接從最小表示法處轉移,若是定義輪換相同,則本質不一樣的串根據polya定理大約爲$o(\frac{2^{n}}{n})$,暴力$o(n^{2})$統計複雜度相同)class

進一步的,只須要選擇最大值最大的$n$列(相同任取)便可,若是在另一列選擇,那麼這$n$列中必定有一個列被選擇,同時那一列中能夠任意旋轉,用該列最大值來替換這「另一列」必定不劣二進制

最終時間複雜度爲$o(Qn3^{n}+Qn^{2}2^{n})$,能夠經過im

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk= watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=
 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\n",f[m][(1<<n)-1]);
46     }
47     return 0;
48 }
View Code
相關文章
相關標籤/搜索