首页 > 其他分享 >1363的美食 方法记录

1363的美食 方法记录

时间:2022-10-13 10:00:07浏览次数:63  
标签:right 记录 int 矩阵 1363 美食 midr left

1363的美食

题目背景

1363看到一个送分题,于是他宣布上不了70分就吃()。

题目描述

然而他发现题目其实有点东西,于是他爆炸了,零分。于是他开始吃(),现在他有两个 \(n × m\) 的矩阵状的() \(A\) 和 \(B\),他可以进行若干次食用。每次食用他可以使 \(A\) 或 \(B\) 的某一行或者某一列的所有元素增加 \(1\)。但是他有强迫症,虽然他很能吃,但是必须看到 \(A\)、\(B\) 相等才肯一口闷。

于是小D很头疼,他想问问你按上述规则,至少要吃多少次,才能使 \(A\) 和 \(B\) 相等。

输入格式

第一行一个正整数 \(T\),表示数据组数。

每组数据的第一行两个正整数 \(n\), \(m\)。

接下来 \(n\) 行,每行 \(m\) 个非负整数 \(A_{i,j}\),表示矩阵 \(A\)。

接下来 \(n\) 行,每行 \(m\) 个非负整数 \(B_{i,j}\),表示矩阵 \(B\)。

输出格式

对于每组数据,输出一行一个整数表示答案。如果无论怎么吃都不能使得 \(A\) 和 \(B\) 相等,输出 \(−1\)。

样例 #1

样例输入 #1

1
3 3
1 1 1
1 1 1
1 1 1
3 2 2
2 1 1
2 1 1

样例输出 #1

2

提示

对于 10% 的数据,\(n\times m\le 5\)

对于 30% 的数据,\(n\times m\le100\)

对于 60% 的数据,\(n\times m\le 10^4\)

对于 100% 的数据,\(n,m,n\times m\le 10^5\),\(1\le T\le 5\),\(A_{i,j},B_{i,j}\le 10^9\)

题解

美食(大嘘)

通过审题,我们知道\(1363\)需要事先处理\(a,b\)两个矩阵。为了方便料理,我们可以先处理出一个\(d\)矩阵,各个位置的元素对应地,有\(d=a-b\).因为对于\(a\)来说,\(b\)某元素加1就相当于\(a\)中对应位置的元素减1.所以,我们就只需要通过使\(d\)矩阵的某一行或某一列的元素加1或减1,来满足\(1363\)挑剔的胃。最终若是能将\(d\)矩阵的每个元素都变成\(0\),则说明矩阵\(a=b\).

现在我们来想想,一个什么样的\(d\)矩阵才能入得了\(1363\)的法眼?不妨以下面的矩阵为例。

考虑如下策略:先固定矩阵的第\(1\)行(即不作加减处理),然后对于下面的第\(2~n\)行,我们想办法给每一行加上或减去一个数,使得该行能和第\(1\)行对应相等。

处理后就变成这种样式:

接着再考虑每一列,这时我们会发现每一列上的数都是一样的。所以我们只需要让每一列都减去对应位置第一行的数就可以将\(d\)矩阵清零。

然后就变成了一群漂亮的\(0\).

请注意,以上都是建立在\(d\)矩阵是可以被料理成\(1363\)满意的样式的基础上的。同时,若这种方法行得通,则这将是一种最“稳妥”的方法。“稳妥”的含义是,若这种方法都无法使\(1363\)满足,则再无别的方法满足他了,应当输出\(-1\).

考虑什么情况下\(1363\)注定无法被满足。

回顾一下之前的第一步(就是固定第一行的那个),倘若我们要将矩阵\(d\)的每一行都彼此相等,那么矩阵\(d\)每行间就应该具有“等差性”

如何理解“等差性”?举个例子,如果第\(1\)行的第\(1\)个数和第\(2\)个数的差为\(n\),那么第\(2~n\)行的第\(1\)个数和第\(2\)个数的差都应该为\(n\),其它位置也应该满足此性质。如果有任何位置不满足,就直接输出\(-1\).

如此以来,我们要么输出\(-1\)走人,要么就得到一种最“稳妥”的方案。接下来的工作就是得到最优的方案。

通过上文的定义,我们知道:

\(Ans=\sum_{i=1}^{n} \left | x_i \right | +\sum_{j=1}^{m} \left | y_j \right |\)


(其中,\(x={0,-1,-2},y={-1,-2,-3}\))

我们的目的是使\(Ans\)尽可能地小。现考虑对\(x\)数组中每个元素加上一个数\(D\),相应地,\(y\)数组中每个元素减去一个数\(D\).这样下来原矩阵依然是可以满足\(1363\)的,那\(Ans\)会有变化吗?上文举的例子不咋好,因为“稳妥”方案就是最优方案,我们来看下面的例子。

上图红字展示的就是一种“稳妥”的策略,我们可以通过上述的方法来优化它。

可以将\(y+D,x-D\)从而得到以下策略:

这就是一个最优的策略。

那么如何得到这个\(D\)呢?再举几个例子,不难发现\(D\)与\(Ans\)的大小关系是一个单峰函数。即是说,对于最优的\(D\),无论\(D+1\)还是\(D-1\)都会使\(Ans\)更劣。那么,我们就可以选择三分法处理这个问题。

三分法

应用场景

二分法使用的场景是单调函数,也就是一次函数;三分法使用的场景是单峰函数,也就是二次函数。

算法实现

首先,我们需要两个点将全域(\(left~right\))分为三段。

midl=left+(right-left)/3;
midr=right-(right-left)/3;

如果\(midl\)比\(midr\)更加靠近最优解,令\(right=midr-1\)(舍弃远离的那一段)
如果\(midr\)比\(midl\)更加靠近最优解,令\(left=midl+1\)(舍弃远离的那一段)

具体到这道题,我们判断最优解的依据就是\(Ans\)的大小。

这样,每一轮迭代都会把查找范围限制在原来的\(2/3\),直到最终逼近最优解。

AC代码(各部分代码功能见注释)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long
using namespace std;
const int N=100005;
const int inf=2147483600;
int t;
int n,m;
int x[N],y[N];
int minn(int a,int b)
{
	return a<b?a:b;
}
int maxx(int a,int b)
{
	return a>b?a:b;
}
int abss(int k)
{
	return k>0?k:-k;
}
int check(int k)//判断midl和midr孰离最优解近 
{
	int res=0;
	for(int i=1;i<=m;i++) res+=abss(y[i]-k);
	for(int i=1;i<=n;i++) res+=abss(x[i]+k);
	return res;
}
int tri_s(int l,int r)//三分! 
{
	while(l<r)
	{
		int midl=l+(r-l)/3;
		int midr=r-(r-l)/3;
		if(check(midl)>check(midr)) l=midl+1;
		else r=midr-1;
	}
	return check(l);
}
signed main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d",&n,&m);
		int a[n+5][m+5],b[n+5][m+5],d[n+5][m+5];
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		memset(d,0,sizeof(d));
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
				scanf("%d",&a[i][j]);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
				scanf("%d",&b[i][j]);
				
		for(int i=1;i<=n;i++)//处理出d矩阵 
			for(int j=1;j<=m;j++)
				d[i][j]=a[i][j]-b[i][j];
				
		for(int i=1;i<=m;i++)//处理出y数组 
			y[i]=d[1][i];
			
		bool flag=0;
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<m;j++)
			{
				if(d[i][j]-d[i][j+1]!=d[1][j]-d[1][j+1])//出现不满足“等差性” 
				{
					puts("-1");//直接输出-1跑路 
					flag=1;
					break;
				}
			}
			x[i]=d[i][1]-d[1][1];
			if(flag) break;
		}
		if(flag) continue;
		printf("%lld\n",tri_s(-inf,inf));//在全域范围内三分找D 
	}
	return 0;
}

标签:right,记录,int,矩阵,1363,美食,midr,left
From: https://www.cnblogs.com/fish4174/p/16787083.html

相关文章

  • IIS相关发布错误解决记录
    HRESULT代码 0x80070021错误消息:应用程序“应用程序名称”中的服务器错误HTTP错误500.19-内部服务器错误HRESULT:0x80070021对HRESULT的说明由于此页相关的配置数......
  • 2022 十月 VP 记录
    10.8EducationalCodeforcesRound136(RatedforDiv.2):5/6,performance261010.9CodeforcesRound#743(Div.1):2/6,unrated看不到performance10.12CodeforcesR......
  • 记录 debian intel nvidia 笔记本安装显卡驱动详细过程
    目录识别显卡检测并安装显卡驱动配置/etc/X11/xorg.conf/etc/lightdm/display_setup.sh/etc/lightdm/lightdm.conf重启系统,完成所有配置检测结果以下步骤全部根据官方文档......
  • 【博学谷学习记录】超强总结,用心分享 | MySQL的锁_笔记
    目录全局锁表级锁表级锁-表锁表级锁-元数据锁表级锁-IS(意向共享锁)与IX(意向排他锁)行级锁间隙锁例子临键锁和记录锁例子全局锁概念:全局锁就是对整个数据库实例加......
  • 关于Gitlab-clone代码后-并修改-最后合并master主分支的操作过程记录
    因需要对master分支的代码,进行一些修改,笔者是项目的Maintainer权限,在此记录一下过程1、先将项目代码clone到本地,默认情况,需要先有~/.ssh/id_rsa,实现登录过程中的认证QQ-......
  • 记录下linux命令关于chown
    题目:关于对其他用户(自己创建的user1)下的目录test及其下的所有文件的所有者改成bin,所属组改成daemon。一开始切换到user1下却操作不了修改文件为bin用户,chown-R也没用......
  • 2022-10-12 vue+uniapp+echarts 使用记录
    第一步:安装echartsnpmiecharts第二步:在main.js引入echartsimportechartsfrom'echarts'Vue.prototype.$echarts=echarts第三步:在项目中使用<template>......
  • 养成记录和积累的好习惯
    养成记录和积累的好习惯前言:工作后一直在反思,为什么明明自己花了好多时间学习,但总是没有什么成系统的学习成果产出?后来想了一个,就是自己的知识积累没有系统,知识点都是处......
  • letcode刷题记录-day01-两数之和
    题目:两数之和描述给定一个整数数组nums 和一个整数目标值target,请你在该数组中找出和为目标值target 的那 两个 整数,并返回它们的数组下标。你可以假设每种输......
  • wxjava服务商模式记录
    1.微信支付服务商必须绑定与小程序appid的授权关系。产品中心-appid账号管理-关联更多。然后在小程序登录--微信支付--确认。2.服务商功能-开发配置-特约商户appid配置-......