[cf1219G]Harvester
分类讨论(以下仅考虑行,列的情况):
1.4行的,求出每一行的和后找到4个最大值即可;
2.3行1列,枚举列,再将每一行最大值减去那一列的值后取3个最大值得和即可;
3.2行2列,发现行和列是等价的,因此可以通过旋转使得$m\le n$,又因为$nm\le 10^5$,所以$m\le \sqrt{10^5}$,枚举两列后用同样的做法求出最大值即可
最终复杂度$o(nm\codt \min(n,m))$,也就是根号的复杂度
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define ll long long 5 int n,m; 6 ll ans,b[N],s1[N],s2[N]; 7 vector<int>a[N]; 8 bool cmp(ll x,ll y){ 9 return x>y; 10 } 11 ll qu(ll *a,int n,int k){ 12 if (n<k)return 0; 13 ll x; 14 for(int i=1;i<=k;i++)b[i]=0; 15 for(int i=1;i<=n;i++){ 16 x=a[i]; 17 for(int j=1;j<=k;j++) 18 if (x>b[j])swap(x,b[j]); 19 } 20 x=0; 21 for(int i=1;i<=k;i++)x+=b[i]; 22 return x; 23 } 24 int main(){ 25 scanf("%d%d",&n,&m); 26 for(int i=1;i<=n;i++){ 27 a[i].push_back(0); 28 for(int j=1;j<=m;j++){ 29 scanf("%lld",&ans); 30 a[i].push_back(ans); 31 s1[i]+=a[i][j]; 32 s2[j]+=a[i][j]; 33 } 34 } 35 ans=max(qu(s1,n,4),qu(s2,m,4)); 36 for(int i=1;i<=n;i++){ 37 for(int j=1;j<=m;j++)s2[j]-=a[i][j]; 38 ans=max(ans,s1[i]+qu(s2,m,3)); 39 for(int j=1;j<=m;j++)s2[j]+=a[i][j]; 40 } 41 for(int j=1;j<=m;j++){ 42 for(int i=1;i<=n;i++)s1[i]-=a[i][j]; 43 ans=max(ans,s2[j]+qu(s1,n,3)); 44 for(int i=1;i<=n;i++)s1[i]+=a[i][j]; 45 } 46 if (n<=m) 47 for(int i=1;i<n;i++) 48 for(int j=i+1;j<=n;j++){ 49 for(int k=1;k<=m;k++)s2[k]-=a[i][k]+a[j][k]; 50 ans=max(ans,s1[i]+s1[j]+qu(s2,m,2)); 51 for(int k=1;k<=m;k++)s2[k]+=a[i][k]+a[j][k]; 52 } 53 else 54 for(int i=1;i<m;i++) 55 for(int j=i+1;j<=m;j++){ 56 for(int k=1;k<=n;k++)s1[k]-=a[k][i]+a[k][j]; 57 ans=max(ans,s2[i]+s2[j]+qu(s1,n,2)); 58 for(int k=1;k<=n;k++)s1[k]+=a[k][i]+a[k][j]; 59 } 60 printf("%lld",ans); 61 }