是dp还是贪心?邓哲也的矩阵(优先队列)

7 篇文章 0 订阅
2 篇文章 0 订阅

题目如下:

给你个n行m列的矩阵,你可以操作k次,每次把一行或者一列每个数都减p,然后获得这一行或者这一列原来所有数的和的分数.
问k次操作后能够得到的最大分数.

思考.

首先想到一个贪心,每次选择最大的一行或者一列进行操作.
可惜样例里有一个数据是这样的.

n=1 m=2 k=3 p=2
3 3

这时候这种贪心算出来只有7,但是手膜一下可以算出8来.
那么这种贪心就不对了.
那难道就不能贪心了吗?
怎么可能!你只有两种方法,操作行和操作列.很明显对于单独操作行和单独操作列来说,都可以应用这样的贪心.

/*
那么只有操作几次的问题了.我们枚举操作行的次数i,则操作列的次数就是k-i.
再膜一下你会发现操作的顺序不影响答案.所以我们就可以贪心去分别跑操作行i次可以得到的最大分数,列也同理.
最后从0到k枚举一遍.
等等!操作行之后会影响列的!得减掉一个数字!
那么我们直接先操作i次行.
这i次操作使得每一次每一列都减掉了p.
所以你在(k-i)次对列的操作中每一次实际上都少了i*p,因此这一部分要减掉.
接下来就是答案了.
*/
#pragma GCC optimize("inline,Ofast",3)
#include<bits/stdc++.h> //Ithea Myse Valgulious
namespace chtholly{
typedef long long ll;
#define re0 register int
#define rec register char
#define rel register ll
#define gc getchar
#define pc putchar
#define p32 pc(' ')
#define pl puts("")
/*By Citrus*/
inline int read(){
  int x=0,f=1;char c=gc();
  for (;!isdigit(c);c=gc()) f^=c=='-';
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return f?x:-x;
  }
template <typename mitsuha>
inline bool read(mitsuha &x){
  x=0;int f=1;char c=gc();
  for (;!isdigit(c)&&~c;c=gc()) f^=c=='-';
  if (!~c) return 0;
  for (;isdigit(c);c=gc()) x=(x<<3)+(x<<1)+(c^'0');
  return x=f?x:-x,1;
  }
template <typename mitsuha>
inline int write(mitsuha x){
  if (!x) return 0&pc(48);
  if (x<0) x=-x,pc('-');
  int bit[20],i,p=0;
  for (;x;x/=10) bit[++p]=x%10;
  for (i=p;i;--i) pc(bit[i]+48);
  return 0;
  }
inline char fuhao(){
  char c=gc();
  for (;isspace(c);c=gc());
  return c;
  }
}using namespace chtholly;
using namespace std;
const int yuzu=1e6;
ll hang[1010],lie[1010];
priority_queue<ll> zxy,llx;
/*zxy:hang llx:lie*/
ll dph[yuzu|10],dpl[yuzu|10];

int main(){
int i,j,n=read(),m=read(),k=read(),p=read();
for (i=1;i<=n;++i){
  for (j=1;j<=m;++j){
    int x=read();
    hang[i]+=x;
    lie[j]+=x;
    }
  }//求出每行每列的和.
for (i=1;i<=n;++i) zxy.push(hang[i]);
for (i=1;i<=m;++i) llx.push(lie[i]);
/*zxy:hang llx:lie*/
for (i=1;i<=k;++i){
  ll t=zxy.top();zxy.pop();
  dph[i]=dph[i-1]+t;
  zxy.push(t-1ll*p*m);//每一次从优先队列里取出最大的和,加入答案,对这一行或者列都减掉p.(行即减掉m个p,列即减掉n个p).
  t=llx.top();llx.pop();
  dpl[i]=dpl[i-1]+t;
  llx.push(t-1ll*p*n);
  }
ll ans=-1e18;//这里-inf必须要足够小才行.
for (i=0;i<=k;++i){
  ans=max(ans,dph[i]+dpl[k-i]-1ll*(k-i)*i*p);//最后跑一遍求一边最大值.
  }write(ans);
}

开了个臭氧优化,从1200多ms瞬间变成120ms,直接上天.
这样答案就出来了,时间复杂度 O(klog(k)) O ( k ∗ l o g ( k ) ) .谢谢大家.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值