选数字
题目描述 LYK 找到了一个 n*m 的矩阵,这个矩阵上都填有一些数字,对于第 i 行第 j 列的位置上 的数为 ai,j。
由于它 AK 了 noip2016 的初赛,最近显得非常无聊,便想到了一个方法自娱自乐一番。 它想到的游戏是这样的
:每次选择一行或者一列,它得到的快乐值将会是这一行或者一列的 数字之和。之后它将该行或者该列上的数字都减去 p(之后可能变成负数)。
如此,重复 k 次,它得到的快乐值之和将会是它 NOIP2016 复赛比赛时的 RP 值。 LYK 当然想让它的 RP 值尽可能高,于是它来求助于你。
数据范围 总共 10 组数据。
对于第 1,2 组数据 n,m,k<=5。
对于第 3 组数据 k=1。 对于第 4 组数据 p=0
。 对于第 5,6 组数据 n=1,m,k<=1000。
对于第 7,8 组数据 n=1,m<=1000,k<=1000000。
对于所有数据 1<=n,m<=1000,k<=1000000,1<=ai,j<=1000,0<=p<=100。
思路:
开始没有想到正解,打了60分,还不错。
正解就是把从一维单独取K次,
然后枚举行和列个选了多少次(因为tx+ty=k ,所以,枚举它们的复杂度只有k)
最后,因为我们是单独选的,没有考虑 行对列的影响,也没考虑列对行的影响,所以你要考虑它们互相影响。
想一下:你每选一行,对于ty列中每一列都会减P,所有再减tx*ty个p就行。
60分
#include<iostream> #include<queue> #include<vector> #include<cstdio> #include<algorithm> using namespace std; int n,m,k,p; int a[1200][1200]; priority_queue<long long>q; int main() { freopen("select.in","r",stdin); freopen("select.out","w",stdout); scanf("%d%d%d%d",&n,&m,&k,&p); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); if(k==1) { int maxn=-999999,w,tot=0; for(int i=1;i<=n;i++) { tot=0; for(int j=1;j<=m;j++) tot+=a[i][j]; if(tot>maxn) w=i,maxn=tot; } int maxnn=-99999,ww; for(int j=1;j<=m;j++) { tot=0; for(int i=1;i<=n;i++) tot+=a[i][j]; if(tot>maxnn) maxnn=tot,ww=j; } cout<<max(maxn,maxnn); return 0; } if(p==0) { long long maxn=-9999999,w,tot=0; for(int i=1;i<=n;i++) { tot=0; for(int j=1;j<=m;j++) tot+=a[i][j]; if(tot>maxn) w=i,maxn=tot; } long long maxnn=-999999,ww; for(int j=1;j<=m;j++) { tot=0; for(int i=1;i<=n;i++) tot+=a[i][j]; if(tot>maxnn) maxnn=tot,ww=j; } cout<<(max(maxn,maxnn)*k); return 0; } if(n==1) { if(k<=1000) { long long tot=0,sum; for(int j=1;j<=m;j++) tot+=a[1][j],q.push(a[1][j]-p); long long x,ans=tot,kk=k-2; k--; while(k--) { x=q.top();q.pop(); ans+=x;x-=p; q.push(x); } sum=ans; while(!q.empty()) q.pop(); ans=tot*2; for(int j=1;j<=m;j++) q.push(a[1][j]-2*p); while(kk--) { x=q.top();q.pop(); ans+=x;x-=p; q.push(x); } cout<<max(ans,sum); return 0; } for(int j=1;j<=m;j++) q.push(a[1][j]); long long x,ans=0; while(k--) { x=q.top();q.pop(); ans+=x;x-=p; q.push(x); } cout<<ans; return 0; } if(n*m<=30) { long long maxn=-99999,w,tot=0;long long maxnn=0,ww,ans=0; while(k--) { maxn=-99999,maxnn=-999999; for(int i=1;i<=n;i++) { tot=0; for(int j=1;j<=m;j++) tot+=a[i][j]; if(tot>maxn) w=i,maxn=tot; } for(int j=1;j<=m;j++) { tot=0; for(int i=1;i<=n;i++) tot+=a[i][j]; if(tot>maxnn) maxnn=tot,ww=j; } ans+=max(maxn,maxnn); if(maxn>maxnn) { for(int j=1;j<=m;j++) a[w][j]-=p; }else { for(int i=1;i<=n;i++) a[i][ww]-=p; } } cout<<ans; } return 0; }
#include <cmath> #include <cstdio> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int N=1000005; long long ans,s1[N],s2[N],p1[N],p2[N]; int k,n,m,i,j,p,A; int main() { freopen("select.in","r",stdin); freopen("select.out","w",stdout); scanf("%d%d%d%d",&n,&m,&k,&p); for (i=1; i<=n; i++) for (j=1; j<=m; j++) { scanf("%d",&A); s1[i]+=A;s2[j]+=A; } make_heap(s1+1,s1+1+n); make_heap(s2+1,s2+1+m); for( i=1;i<=k;i++) { p1[i]=p1[i-1]+s1[1]; pop_heap(s1+1,s1+1+n); s1[n]-=m*p; push_heap(s1+1,s1+1+n); p2[i]=p2[i-1]+s2[1]; pop_heap(s2+1,s2+1+m); s2[m]-=n*p; push_heap(s2+1,s2+1+n); } ans=-1LL*100000000*100000000; for(int i=0;i<=k;i++) ans=max(ans,p1[i]+p2[k-i]-1LL*i*(k-i)*p); cout<<ans; return 0; }