选数字

题目描述 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;
}
60分

 

#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;
}
满分代码

 

posted @ 2017-10-07 11:42  浪矢-CL  阅读(246)  评论(0编辑  收藏  举报