But my words, like |

MessageBoxA

园龄:4年10个月粉丝:4关注:0

CSP模拟 矩阵操作

涉及知识点:就是个推式子+贪心?

前言

感觉有点板,故记录一下以备后续所用。

题意

有两个 n×m 的矩阵 AB,每次操作可以把 A 或者 B 的某一行/列全部 +1,最少几次操作 A=B

思路

首先想到的肯定是构造一个差分矩阵,即 D=BA,问题转化为从一个零矩阵开始每次某一行/列 +11,问多少次操作得到 D。这是因为在 A+1 的操作可以等价为在 B1 的操作。注意:D 中可能有负数。

那么现在问题的规模就从涉及两个矩阵压缩到了一个矩阵上,我们定义 riDi 行的修改,ci 为第 i 列的修改,同样的,ri,ci 也可能为负数。

我们先假设 D 是合法的,此时显然可以得到:

(1){ri=Di,1c1ci=D1,ir1

此时互相代入展开 c1,r1

(2){ri=Di,1D1,1+r1ci=D1,iD1,1+c1

我们就得到了 ri,ci 的表达式。

显然 D 合法的充要条件是 Di,j=ri+cj,我们代入 (1) 得到:

(3)Di,j=Di,1+D1,i(r1+c1)

同时我们也知道 r1+c1=D1,1,因此 D 合法的条件就是,对于每个 i[1,n],j[1,m] 都满足 Di,j=Di,1+D1,iD1,1

接下来我们来计算答案,显然答案为 i=1n|ri|+i=1m|ci|,将 ci(1) 中的表示代入,ri(2) 中的表示代入,我们就得到了一个全部由 r1 表示(其他都是常数)的式子:

(4)Ans=i=1n|Di,1D1,1+r1|+i=1m|D1,ir1|

于是我们会发现,这个式子可以转化为一个 |r1λ| 的形式:

(5)Ans=i=1n|r1(D1,1Di,1)|+i=1m|r1D1,i|

那么此时,根据数学知识,r1 取所有n+mλ 的中位数即可。

代码

为了节约空间,没必要再新开一个 D 数组,故直接用 B 存储差分后的结果。

另外,在编码时,如果 n+m 为偶数,r1 没必要严格取计算中间两个数的平均值,可以证明只要 r1 的取值在这两个数之间(包含这两个数)答案都一样,因此随便取左边或者右边那个数就行。

#include<bits/stdc++.h>
#define getid(x,y) ((x-1)*m+y)
using namespace std;
template<class T>inline void rd(T &x){
    T res=0,f=1;
    char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while('0'<=ch && ch<='9'){res=res*10+ch-'0';ch=getchar();}
    x=res*f;
}
template<class T>inline void wt(T x,char endch='\0'){
    static char wtbuff[20];
    static int wtptr;
    if(x==0){
        putchar('0');
    }
    else{
        if(x<0){x=-x;putchar('-');}
        wtptr=0;
        while(x){wtbuff[wtptr++]=x%10+'0';x/=10;}
        while(wtptr--) putchar(wtbuff[wtptr]);
    }
    if(endch!='\0') putchar(endch);
}
typedef long long LL;
const int MAXN=1e5+5;
int n,m;
LL a[MAXN],b[MAXN],ans;
inline void solve(){
    rd(n);rd(m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            rd(a[getid(i,j)]);
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            rd(b[getid(i,j)]);
            b[getid(i,j)]-=a[getid(i,j)];
        }
    }
    // for(int i=1;i<=n;i++){
    //     for(int j=1;j<=m;j++){
    //         cout<<b[getid(i,j)]<<' ';
    //     }
    //     cout<<endl;
    // }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(b[getid(i,j)]!=b[getid(1,j)]+b[getid(i,1)]-b[getid(1,1)]){
                puts("-1");
                return;
            }
        }
    }
    vector<LL>vec;
    for(int i=1;i<=n;i++)
        vec.push_back(b[getid(1,1)]-b[getid(i,1)]);
    for(int i=1;i<=m;i++)
        vec.push_back(b[getid(1,i)]);
    nth_element(vec.begin(),vec.begin()+vec.size()/2,vec.end());
    LL x=vec[vec.size()/2];
    ans=0;
    for(auto it:vec){
        ans+=abs(it-x);
    }
    wt(ans,'\n');
}
int main(){
    int t;
    rd(t);
    while(t--){
        solve();
    }
    return 0;
}

本文作者:MessageBoxA

本文链接:https://www.cnblogs.com/SkyNet-PKN/p/18406568

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   MessageBoxA  阅读(23)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 evening Corn Wave
  2. 2 Группа крови Кино
  3. 3 The Sound Of Silence Simon & Garfunkel
  4. 4 dB doll YUE.STEVEN
Группа крови - Кино
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.