AT_agc061_d [AGC061D] Almost Multiplication Table题解

非常好的构造题!山东省集被出了。

应该通俗易懂吧......

思路

考虑二分答案 m i d mid mid,设 L i , j = a i , j − m i d L_{i,j}=a_{i,j}-mid Li,j=ai,j−mid, R i , j = a i , j + m i d R_{i,j}=a_{i,j}+mid Ri,j=ai,j+mid,则 X i Y j ∈ L i , j , R i , j X_iY_j\in L_{i,j},R_{i,j} XiYj∈Li,j,Ri,j。我们只需要判断是否有符合条件的构造即可。

不妨设 X n ≤ Y m X_n\le Y_m Xn≤Ym( X n ≥ Y m X_n\ge Y_m Xn≥Ym 同理)埋下伏笔,设 S i S_i Si 为目前 X i X_i Xi 的最小值(初始为 1 1 1), D i D_i Di 为目前 Y i Y_i Yi 的最大值,初始为 2 × 10 9 2\times 10^9 2×109。考虑逼近法,逐渐逼近 X i X_i Xi 与 Y i Y_i Yi 的真实值。

我们考虑依次进行以下操作:

  1. 从前往后枚举 S i S_i Si,若 S i ≤ S i − 1 S_i\le S_{i-1} Si≤Si−1,则 S i ⟵ S i − 1 + 1 S_i\longleftarrow S_{i-1}+1 Si⟵Si−1+1。同时枚举 D j D_j Dj,若 S i D j < L i , j S_iD_j< L_{i,j} SiDj<Li,j,由于 D j D_j Dj 已经是 Y j Y_j Yj 的最大值了,所以只能令 S i ⟵ ⌈ L i , j D j ⌉ S_i \longleftarrow \left \lceil \frac{L_{i,j}}{D_j} \right \rceil Si⟵⌈DjLi,j⌉。
  2. 从后往前枚举 D i D_i Di,若 D i ≥ D i + 1 D_i\ge D_{i+1} Di≥Di+1,则 D i ⟵ D i + 1 − 1 D_i\longleftarrow D_{i+1}-1 Di⟵Di+1−1。同时枚举 S j S_j Sj,若 S j D i > R j , i S_jD_i> R{j,i} SjDi>Rj,i,由于 S j S_j Sj 已经是 X j X_j Xj 的最小值了,所以只能令 D i ⟵ ⌊ L j , i S j ⌋ D_i\longleftarrow \left \lfloor \frac{L_{j,i}}{S_j} \right \rfloor Di⟵⌊SjLj,i⌋。
  3. 若 S i S_i Si 与 D j D_j Dj 均符合题意,则 S i S_i Si 与 D j D_j Dj 是 X i X_i Xi 与 Y j Y_j Yj 的一组合法构造。
  4. 若 X n > Y m X_n>Y_m Xn>Ym 或 Y m ≤ 0 Y_m\le 0 Ym≤0,则直接返回不合法。

按照上述顺序依次操作构造出的序列显然是对的。下面我们证明一下操作的复杂度:

  1. 显然,每一轮操作中,至少存在一个 S i S_i Si 变大或 D j D_j Dj 变小。
  2. 显然,如果我们想让惩罚值最小, X i Y j X_iY_j XiYj 不能超过 10 9 10^9 109(否则我还不如直接给 X X X 赋值为 1 , 2 , ... , n 1,2,\dots ,n 1,2,...,n,将 Y Y Y 赋值为 1 , 2 , ... , m 1,2,\dots ,m 1,2,...,m)。
  3. 还记得前面说的吗?要求 X n ≤ Y m X_n\le Y_m Xn≤Ym,又由于 X i Y j ≤ 10 9 X_iY_j\le 10^9 XiYj≤109,所以 X i ≤ 10 9 ≈ 3 × 10 4 ≤ Y j X_i\le \sqrt{10^9}\approx 3\times 10^4 \le Y_j Xi≤109 ≈3×104≤Yj。则每个 X i X_i Xi 最多增加 3 × 10 4 3\times 10^4 3×104 次,每个 Y j Y_j Yj 最多减少 3 × 10 4 3\times 10^4 3×104 次。故总轮数不会超过 3 × 10 4 ( n + m ) ≈ 3 × 10 5 3\times 10^4(n+m)\approx 3\times 10^5 3×104(n+m)≈3×105。

证明完毕。

加上外面的二分与具体实现,总时间复杂度为 O ( ( n + m ) n m V log ⁡ V ) O((n+m)nm\sqrt{V} \log_{}{V} ) O((n+m)nmV logV),其中 V = 2 × 10 9 V=2\times 10^9 V=2×109。(算下来不到 10 7 10^7 107)

代码

注意数组的第一维与第二维不要写反,不然调起来可能比较麻烦。

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
long long n,m,a[10][10],l[10][10],r[10][10];
long long s[10],d[10];
bool check(long long x)
{
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) l[i][j]=max(1ll,a[i][j]-x),r[i][j]=a[i][j]+x;
	for(int i=1;i<=n;i++) s[i]=1;
	for(int i=1;i<=m;i++) d[i]=2e9;
	bool op=0;
	while(1)
	{
		bool flag=0;
		for(int i=1;i<=n;i++)
		{
			if(i-1&&s[i]<=s[i-1]) flag=1,s[i]=s[i-1]+1;
			for(int j=1;j<=m;j++)
				if(s[i]*d[j]<l[i][j]) flag=1,s[i]=(l[i][j]+d[j]-1)/d[j];	
		}
		for(int i=m;i>=1;i--)
		{
			if(i+1<=m&&d[i]>=d[i+1]) flag=1,d[i]=d[i+1]-1;
			for(int j=1;j<=n;j++)
				if(s[j]*d[i]>r[j][i]) flag=1,d[i]=r[j][i]/s[j];
		}
		if(s[n]>d[m]||d[1]<=0) op=1;
		if(op||!flag) break;
	}
	if(!op) return 1;
	op=0;
	for(int i=1;i<=n;i++) s[i]=2e9;
	for(int i=1;i<=m;i++) d[i]=1;
	while(1)
	{
		bool flag=0;
		for(int i=1;i<=m;i++)
		{
			if(i-1&&d[i]<=d[i-1]) flag=1,d[i]=d[i-1]+1;
			for(int j=1;j<=n;j++)
				if(d[i]*s[j]<l[j][i]) flag=1,d[i]=(l[j][i]+s[j]-1)/s[j];	
		}
		for(int i=n;i>=1;i--)
		{
			if(i+1<=n&&s[i]>=s[i+1]) flag=1,s[i]=s[i+1]-1;
			for(int j=1;j<=m;j++)
				if(s[i]*d[j]>r[i][j]) flag=1,s[i]=r[i][j]/d[j];
		}
		if(d[m]>s[n]||s[1]<=0) op=1;
		if(op||!flag) break;
	}
	if(!op) return 1;
	return 0;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++) cin>>a[i][j];
	long long l=0,r=2000000000,ans=-1;
	while(l<=r)
	{
		long long mid=(l+r)>>1ll;
		if(check(mid)) r=mid-1,ans=mid;
		else l=mid+1;
	}
	cout<<ans<<"\n";
	check(ans);
	for(int i=1;i<=n;i++) cout<<s[i]<<" ";
	cout<<"\n";
	for(int i=1;i<=m;i++) cout<<d[i]<<" ";
    return 0;
}
相关推荐
happymaker062612 分钟前
LeetCodeHot100——42.接雨水
算法
阿正的梦工坊1 小时前
【Rust】07-错误处理:Option、Result 与 ? 运算符
开发语言·算法·rust
为何创造硅基生物1 小时前
独占指针的创建std::make_unique 本身自带堆出现
c++
kyle~2 小时前
ROS 2 与 Isaac Sim 联合仿真(一)体系架构、环境选型与基础通信闭环
c++·机器人·nvidia·仿真·ros2
努力努力再努力wz2 小时前
【内存管理与高并发内存池系列】从 mmap 到 malloc:文件映射、匿名映射与 glibc 内存分配机制详解
linux·c语言·数据结构·数据库·c++·qt·链表
八解毒剂2 小时前
数据结构-平衡二叉树——对二叉搜索树的优化
数据结构·c++·算法
运行时记录3 小时前
别再手动写提示词了 — SkillOpt 让技能文档自己进化
算法
起床困难户5753 小时前
条款20:协助完成返回值优化
c++
啦啦啦啦啦zzzz3 小时前
算法总结(二分查找、双指针)
c++·算法
qq_8573058193 小时前
python语法
开发语言·python·算法