牛客小白月赛111F题解

题目链接

知识点:扩展欧几里得算法,不定方程
因为觉得官方的题解写的不明所以,所以写了这篇题解。

不妨设最终每个数的值为 ,操作数为 ,数组的和为 ,数组中的最大值为 ,最小值为 。则有

接下来,先用扩展欧几里得求一下这个方程的解,如果无解直接输出 -1。这里还要特判一下 的情况,这种情况下,除非每个数相同,否则都是 -1。现在我们求得了一组解 ,要怎么求最小的 呢?

首先,如果 ,则考虑增大 的同时减小 。具体地,令 为最大的非负整数满足 ,则使 。否则, 不需要减小。

接着,因为每次操作不能将一个 减很多次,则 ;因为不能执行加操作,所以 。上面那组不定方程的整数解可以表示为 ,带入到这两个不等式中,可以得到两个与 有关的不等式,分别是 。解一下就可以得到 的下界,注意向上取整的问题。然后,我们就可以愉快地得到 的最小值了。

代码如下:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+5;
int n, k;
ll sum, mx, mn;
inline void chkmx(ll &x, ll y){
	x = x>y?x:y;
}
inline void chkmn(ll &x, ll y){
	x = x<y?x:y;
}
int ex_euclid(int a, int b, ll c, ll &x, ll &y){
	if(b == 0){
		x=c/a, y=0;
		if(c%a != 0) return -1;
		return a;
	}
	int g;
	ll xx, yy;
	g = ex_euclid(b,a%b,c,xx,yy);
	x=yy, y=xx-a/b*yy;
	return g;
}

int main(){
	scanf("%d%d", &n, &k);
	int g, a, b;
	ll x, y, t=0;
	mn = 1e9+1;
	for(int i=1; i<=n; ++i){//因为只有最大值、最小值和总和有用,所以不需要存下整个数组
		scanf("%lld", &x);
		sum += x;
		chkmx(mx,x); chkmn(mn,x);
	}
	if(mx == mn){
		printf("0\n"); return 0;
	}else if(n == k){
        printf("-1\n"); return 0;
    }

	g = ex_euclid(n,k,sum,x,y);
	if(g == -1){//裴蜀定理,判断是否有解
		printf("-1\n"); return 0;
	}

	a=n/g, b=k/g;
	if(x < mn){//确保最开始的时候y足够小 
		t = (mn-x)/b;
		x+=b*t, y-=a*t;
		t = 0;
	}
	if(y < 0)//y>=0
		chkmx(t, (-y-1)/a+1);
	if(x > mn)//最终得到的数x0应该不大于最小值mn
		chkmx(t, (x-mn-1)/b+1);
	if(mx > x+y)//对最大值减一的次数不超过y次
		chkmx(t, (mx-x-y-1)/(a-b)+1);
	y += a*t;
	printf("%lld\n", y);
	return 0;
}/*
5 4
1 2 3 5 5
output:9
7 6
2 2 3 4 5 6 8
output:26
*/
全部评论

相关推荐

03-15 10:59
已编辑
美团_后端开发(实习员工)
爱写代码的菜code...:哎,自己当时拿到字节offer的时候也在感叹终于拿到了,自己当时最想去的企业就是字节,结果还是阴差阳错去了鹅厂。祝uu一切顺利!!!
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务