• CF446B DZY Loves Modification 【思维/优先队列】By cellur925


    题目传送门

    题目大意:给一个 (n*m) 的矩阵,并进行 (k) 次操作,每次操作将矩阵的一行或一列的所有元素的值减 (p) ,得到的分数为这次修改之前这一列/一行的元素和,求分数最大值。

    我开始的意识流想法是用一个优先队列维护,先把所有元素插入,然后(k)次每次取出堆顶,减去乘(p)的什么东西,再塞回队中。但是...行与列是会互相影响的鸭,那么怎么搞呢?然后就不会了hh。

    正解是努力打破了行与列之间的相互影响,把行与列分开计算。我们考虑行与列是怎么互相影响的:选择(i)个行,(j)个列,那么这里(j=k-i)。显然会产生(i)*((k-i))个交点,我们需要另减去这些交点的贡献。

    我们分别处理出行&列后,枚举最终的(i)就好了:)

    
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    
    using namespace std;
    typedef long long ll;
    
    int n,m,k,p;
    int f[2018][2018];
    ll hang[2000],lie[2000],hang_cnt[1000900],lie_cnt[1000900];
    ll ans=-1e18;
    priority_queue<ll>q;
    
    int main()
    {
        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",&f[i][j]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                lie[j]+=f[i][j],hang[i]+=f[i][j];
        for(int i=1;i<=m;i++) q.push(lie[i]);
        for(int i=1;i<=k;i++)
        {
            ll tmp=q.top();q.pop();
            lie_cnt[i]=lie_cnt[i-1]+tmp;
            tmp-=1ll*n*p;
            q.push(tmp);
        }
        while(!q.empty()) q.pop();
        for(int i=1;i<=n;i++) q.push(hang[i]);
        for(int i=1;i<=k;i++)
        {
            ll tmp=q.top();q.pop();
            hang_cnt[i]=hang_cnt[i-1]+tmp;
            tmp-=1ll*m*p;
            q.push(tmp);
        }
        for(int i=0;i<=k;i++)
            ans=max(ans,hang_cnt[i]+lie_cnt[k-i]-1ll*i*(k-i)*p);
        printf("%lld
    ",ans);
        return 0;
    }
    

    注意开始数组开小了(k)(1e5)级别的。到现在还犯这种智障错误

  • 相关阅读:
    NYOJ 260
    NYOJ 271
    [转载]《博客园精华集》Winform筛选结果(共105篇)
    在DataGridView控件中加入ComboBox下拉列表框的实现
    给SQL补充一个查看表结构的存储过程
    编写自定义控件之下拉式属性
    PropertyGrid中的枚举显示为中文(转)
    DataGridView 中合并单元格
    树TreeView控件与DataTable交互添加节点(最高效的方法)
    通过键盘方向键控制TreeView节点的移动
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9893177.html
Copyright © 2020-2023  润新知