Codeforces Round 969 (Div. 2) ---C

 problem: (C) Dora and C++

原题链接:https://codeforces.com/contest/2007/problem/C

题目大意:

n个元素的数组c,Dora有a,b两个整数,

在一次操作中,她可以选择以下操作之一。

  • 选择一个整数 i ,使得 1≤i≤n ,并将 wi增加 a 。
  • 选择一个整数 i ,使得 1≤i≤n ,并将 wi增加 b 。

我们把数组 d的范围定义为 max(di)−min(di)。例如,数组 [1,2,3,4][1,2,3,4] 的取值范围是 4−1=3,数组 [5,2,8,2,2,1] 的取值范围是 8−1=7,数组 [3,3,3]的取值范围是 3−3=0 。

经过任意次数的运算后(可能是 0 ),Dora 会计算出新数组的范围。帮助朵拉最小化这个值,求最小化的值。

 不难看出这是一道关于最小极差的问题。

先分析A==B的情况,那么最终答案一定小于A,否则,我们依然可以通过最小值+A,使得数组中所有元素都大于max(wi)减A,这是因为假如之前数组中最小值通过+A变成了最大值,那之前未操作时所有的元素(除去最小元素)都大于这个操作后的最大值减A。那么遍历所以可能的最小值,例如M,进行操作运算,使得所有的元素都在[M,M+A-1]内。其实我第一次看题解的时候不知道这个分析有什么用,跟后面完全没联系。

再分析:贝祖等式https://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity

因为每次都是+A或者+B,根据贝祖等式可以知道,等价于±gcd(A,B)的倍数。那么我们可以这样分析,对于每组数据,当中每个元素都有可能增加A,或B,而增加 A 或 B 相当于在每个元素上添加不同的值,但这些值的差值必须是 AB的整数倍。设d = gcd(A,B),我们可以对每个元素进行mod d 从而进行标准化,使得增加A或者B的操作仅会影响元素mod d 的剩余部分。

下面举例:

假设 a = 8b = 12,那么 d = __gcd(8, 12) = 4。这意味着无论我们对数组元素进行多少次 ab 的加法操作,最终的元素变化只会以 4 为单位。例如:

  • w[i] += 8w[i] += 12,可以看成 w[i] += 4 的倍数。

因此,我们只需要关心每个元素 w[i] 在模 的情况下的余数,这样我们可以把元素分成几类,每一类的元素的模值相同。对于这些元素,只需要考虑它们在模值相同的情况下的最小差异。

其实看到这里的时候,我发出了疑问,是真的不知道,就是很菜,取模之后不会影响最大值的地位吗?然后我就去百度了。

  • 相对差异不变:对数组每个元素进行取模d时,实际上是消除元素之间的“整倍数”部分的差异,这样做不会改变元素之间相对大小的关系。
  • 元素的周期性:取模d是在d的周期内进行的,类似于在一个循环内的操作,所有不会影响整体的排序和比较

把所有元素标准化之后,就可以开始枚举查找了。

#include<bits/stdc++.h>
using namespace std;
void solve()
{
	int n,a,b;cin>>n>>a>>b;
	int c = __gcd(a,b);
	int w[n+1]={0};
	for(int i = 0;i < n;i++)
	{
		cin>>w[i];
		w[i] = w[i] % c;
	}
	sort(w,w+n);//枚举之前要排序
	int ans = w[n-1] - w[0];//ans初始值是最初的极差
	for(int i = 0;i < n;i++)
	{
		ans = min(ans,w[i] + c - w[i+1]);
//因为是有序数组,并且进行了%c的操作,所以数组中不会出现比c还大的数,所以当元素加上c之后就变成了数组中最大的元素,它后面的第一个元素就变成了最小元素。
	}
//	cout<<endl;
//	cout<<"下面是这道题的答案:"<<endl;
	cout<<ans<<endl;
//	cout<<"答案结束"<<endl;
//	cout<<endl;
}
int main()
{
	int t;cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值