Wannafly挑戰賽26-B 冥土追魂
阿新 • • 發佈:2018-12-15
思路:對於行列選取,是選擇所有行中的最大值的最小值,當是並不能用貪心來做,例如
2 2 2
7 8
1 9
如果用貪心的話就是7+8=15,但是最小值是1+9=10
對於a[i][j]行按照由大到小排序,列按照行總和由小到大排序,選取順序應該是以每次選擇一整行來考慮的,即若k>=m,則選取前m個數一定是選取一整行的數的,可以這樣考慮借鑑部落格Wannafly挑戰賽26: B. 冥土追魂(思維題)
假設第1行選擇了前x個數字, 第2行選擇了前y個數字,且x, y<m(都沒選滿一行)
首先肯定a[2][y+1]>a[1][x] (如果a[2][y+1]<=a[1][x]的話,那麼選擇a[2][y+1]更優,而不會選a[1][x]了) 那麼可以得出a[2][y+1]>a[1][x] → a[2][y]>a[1][x] → a[2][y]>a[1][x+1],這樣的話如果第二行選擇前y-1個數字,第一行選擇前x+1個一定更優
t1=k/m,t2=k%m, 那麼可以對於t2可以列舉所有行,在取前t1(不包含t2選取行)行,儲存最小值即可
Code :
#include<iostream> #include<algorithm> using namespace std; typedef long long LL; const int MAX_N=1005; const int MAX_M=1005; int n,m,s; int a[MAX_N][MAX_M]; struct node{ LL Sum[MAX_M]; int id; bool operator<(const node &p)const{ return Sum[m]<p.Sum[m]; } }d[MAX_N]; bool cmp(const int &a,const int &b){ return a>b; } int main() { ios::sync_with_stdio(false); while(cin>>n>>m>>s){ for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) cin>>a[i][j]; for(int i=1;i<=n;++i) sort(a[i]+1,a[i]+m+1,cmp); for(int i=1;i<=n;d[i].id=i++) for(int j=1;j<=m;++j) d[i].Sum[j]=d[i].Sum[j-1]+a[i][j]; sort(d+1,d+n+1); LL ans=1e18,num; for(int i=1;i<=n;++i) { num=d[i].Sum[s%m]; for(int j=1,t=s/m;j<=n&&t>0;++j) { if(i==j&&s%m) continue; num+=d[j].Sum[m]; --t; } ans=min(ans,num); } cout<<ans<<endl; } return 0; }