Pinely Round 3 (Div. 1 + Div. 2) D. Split Plus K 蒟蒻补题

前前天写了cf的比赛题,很不幸被虐的很惨,再次后来慢慢补提,现在感觉这个题不错写一下自己的心得。

这个图片是题

大致意思就是有T组数据,每组数据有n个数,输入n和k,现在你可以选择一个数x,把x删去,并在找到两个数y和z,并且要满足y+z == x+k(双等,突出严谨),把它们添到数组中,问最后能不能把这个数组里的数最终变为全部相等,如果不能的话输出-1,能的话输出最小的次数。OK,题意介绍完毕,下面开始分析:

题干说要选择一个数加上k后删去变成两个数,即ai+k=y+z,我们不妨设每个 ai 经过 ri 次变化后变成最终的数 ans,这里可能会有一个疑惑,ai + k不是变成另外两个数y,z没有了吗?ai 在这个数组中确实没有了,但它留下来的影响还在,即有这样一个关系 ai + k = y + z,如果y和z不相等的话,之后我们在后续的操作中会对 y 和 z , 进行一样的的操作,比如说y + k = m + n,这样是不是相当于,在 ai那边再加了一个k,变成 ai + 2k = m + n + z,如此不断操作下去,直到右边的数全部相等,根据上边假设我们操作了 ri 次,我们最终会得到一个关系式 ai + ri * k = (ri+1)*ans,然后我们就可以愉快的化简,ri = (ai - ans) / (ans-k),然后现在我们得到这个式子,乍一看啥都看不出来,因为上下都有未知量ans,所以我们就可以进行分式,把上边变成(ai - k - ans +k),然后进行变换,动手划两下,可以变成 ri = (ai - k)/(ans-k) - 1,然后就来到重点了,我们是不是要求 ri 尽可能小,所以 ans - k是不是要尽可能地大?ans - k 是不是要对每一个 ai - k 进行相除,所以ans - k 要做到:1.能被每个 ai -k 除尽;2.它要尽可能大,所以我们能联想到什么?是不是所有ai - k的最大公因数?然后再对所有 ri 相加即可。OK,想到这里你已经了解这道题的主要轮廓了,下面介绍一些细节:

上面我们是不是只讨论了存在最小值的情况,但题中还说如果做不到的话输出 -1,所以我们还需要判断有没有不能化成全部相等的情况。来让我们回过头观察ai +k == y + z,y和z如果存在的话,来让我们感性理解一下,最终不论哪个 ai 我们右边是不是换成了一个相等的数,所以在这个过程中能不能存在一些ai大于k,一些ai小于k?肯定不行吧,这会导致右边的数变得不相等,所以要么全部的 ai 大于k,要么全部的 ai 小于k,即如果排序后有(a[1]<=k&&a[n]>k) II (a[1]<k&&a[n]>=k),那么就可以输出-1了。还有一种情况,ai = k,此时分母为零,我们要单独判断,还有一样情况 ai 全部相等,这两种情况可以放在一块判断,即排序后a[1]==a[n],输出0。

下面贴上代码:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

long long n, k, t;
long long a[200010];

long long gcd(long long x, long long y)
{
	while (y)
	{
		long long c = x % y;
		x = y;
		y = c;
	}

	return x;
}

void solve()
{
	cin >> n >> k;

	memset(a, 0, sizeof a);//及时清理a[i]

	long long ans = 0;
	long long g = 0;
	long long sum = 0;//防止污染后边的sum!!!

	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		g = gcd(g, a[i] - k);//自己手搓一个gcd
	}

	sort(a + 1, a + 1 + n);

	if (a[1] == a[n])
	{
		cout << 0 << endl;
		return;
	}
	if ((a[1]<=k && a[n]>k)||(a[1]<k && a[n]>=k))
	{
		cout << -1 << endl;
		return;
	}

	for (int i = 1; i <= n; i++)
	{
		ans += ((a[i] - k) / g - 1);
	}
	cout << ans << endl;
	return;
}

int main()
{
	cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}

这是蒟蒻对这道题的浅薄看法

  • 23
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值