CSP模拟 矩阵操作
1.NOIP模拟 排序2.NFLS 231031 比赛总结3.JOI2013Final/LOJ2763 现代豪宅4.省选模拟 序列5.省选模拟 过路费6.NOI模拟 序列7.NOI模拟 大战波特8.NOI模拟 Mizuki 与进化9.NOI模拟 刀客球10.NOI模拟 真夏は誰のモノ11.NOI模拟 树数术12.NOI模拟 序列13.NOI模拟 GCD14.NOI模拟 开关15.NOI模拟 排序幻觉16.NOI模拟 UTF-817.NOI模拟 捉迷藏18.退背包简介/NOI模拟 卖画19.CSP模拟 取模
20.CSP模拟 矩阵操作
21.AGC007F Shik and Copying String22.洛谷P10336 [UESTCPC 2024] 2-聚类算法23.NFLS 241014 比赛总结24.QOJ5173 染色25.洛谷P11183 [ROIR 2018 Day2] 大数据处理涉及知识点:就是个推式子+贪心?
前言
感觉有点板,故记录一下以备后续所用。
题意
有两个 的矩阵 和 ,每次操作可以把 或者 的某一行/列全部 ,最少几次操作 ?
思路
首先想到的肯定是构造一个差分矩阵,即 ,问题转化为从一个零矩阵开始每次某一行/列 或 ,问多少次操作得到 。这是因为在 上 的操作可以等价为在 上 的操作。注意: 中可能有负数。
那么现在问题的规模就从涉及两个矩阵压缩到了一个矩阵上,我们定义 为 第 行的修改, 为第 列的修改,同样的, 也可能为负数。
我们先假设 是合法的,此时显然可以得到:
此时互相代入展开 :
我们就得到了 的表达式。
显然 合法的充要条件是 ,我们代入 得到:
同时我们也知道 ,因此 合法的条件就是,对于每个 都满足 。
接下来我们来计算答案,显然答案为 ,将 用 中的表示代入, 用 中的表示代入,我们就得到了一个全部由 表示(其他都是常数)的式子:
于是我们会发现,这个式子可以转化为一个 的形式:
那么此时,根据数学知识, 取所有 个 的中位数即可。
代码
为了节约空间,没必要再新开一个 数组,故直接用 存储差分后的结果。
另外,在编码时,如果 为偶数, 没必要严格取计算中间两个数的平均值,可以证明只要 的取值在这两个数之间(包含这两个数)答案都一样,因此随便取左边或者右边那个数就行。
#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 中国大陆许可协议进行许可。
合集:
南极企鹅语学校集训
分类:
题目题解 / 贪心题目
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步