Time Limit:3000ms Memory Limit:64MB
题目描述
LYK 找到了一个 n*m 的矩阵,这个矩阵上都填有一些数字,对于第 i 行第 j 列的位置上
的数为 ai,j。
由于它 AK 了 noip2016 的初赛,最近显得非常无聊,便想到了一个方法自娱自乐一番。
它想到的游戏是这样的:每次选择一行或者一列,它得到的快乐值将会是这一行或者一列的
数字之和。之后它将该行或者该列上的数字都减去 p(之后可能变成负数)。如此,重复 k
次,它得到的快乐值之和将会是它 NOIP2016 复赛比赛时的 RP 值。
LYK 当然想让它的 RP 值尽可能高,于是它来求助于你。
输入格式(select.in)
第一行 4 个数 n,m,k,p。
接下来 n 行 m 列,表示 ai,j。
输出格式(select.out)
输出一行表示最大 RP 值。
输入样例
2 2 5 2
1 3
2 4
输出样例
11
数据范围
总共 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。
样例解释
第一次选择第二列,第二次选择第二行,第三次选择第一行,第四次选择第二行,第五
次选择第一行,快乐值为 7+4+2+0+-2=11。
暴力:80分
正解:预处理出选0-k个行的值(前缀和)以及0-k个列的值(前缀和)
枚举选i个行以及k-i个列,但是要减去重复的部分,即行和列的交点处,共有i*(k-i)个焦点
1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #define ll long long 5 using namespace std; 6 inline int read() 7 { 8 int x=0,w=1;char ch=getchar(); 9 while(!isdigit(ch)){if(ch==‘-‘) w=-1;ch=getchar();} 10 while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch-‘0‘),ch=getchar(); 11 return x*w; 12 } 13 const int N=1000100; 14 int n,m,k,p; 15 ll x[N],y[N]; 16 priority_queue<ll>q1,q2; 17 int main() 18 { 19 freopen("select.in","r",stdin); 20 freopen("select.out","w",stdout); 21 n=read();m=read();k=read();p=read(); 22 for(int i=1;i<=n;++i) 23 for(int j=1;j<=m;++j) 24 { 25 int o;o=read(); 26 x[i]+=o;y[j]+=o; 27 } 28 for(int i=1;i<=n;++i) q1.push(x[i]),x[i]=0; 29 for(int j=1;j<=m;++j) q2.push(y[j]),y[j]=0; 30 for(int i=1;i<=k;++i) 31 { 32 ll tmp=q1.top();q1.pop(); 33 x[i]=x[i-1]+tmp; 34 q1.push(tmp-p*m); 35 } 36 for(int i=1;i<=k;++i) 37 { 38 ll tmp=q2.top();q2.pop(); 39 y[i]=y[i-1]+tmp; 40 q2.push(tmp-p*n); 41 } 42 ll ans=-1000000000000000ll; 43 for(int i=0;i<=k;++i) 44 ans=max(ans,x[i]+y[k-i]-p*(ll)i*(k-i)); 45 printf("%lld",ans); 46 return 0; 47 }
最近目标:每一道题都要拿到预期分数。
保证这一点