牛客小白月赛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一切顺利!!!
点赞 评论 收藏
分享
03-14 17:03
C++
第一题:给一个区间[l,&nbsp;r],计算区间中整数的因子数是奇数的个数并输出,比如12的因子数有:1,2,3,4,6,12,因此12不符合条件。这题只要意识到因子数都是成对出现的即可,只有当有2个因子数相等时才会出现奇数情况,比如:1=1*1,&nbsp;4=2*2,&nbsp;9=3*3,81=9*9我是对左右区间开平方取整,然后相减即可,注意想清楚并处理闭区间的特殊情况第二题:给定一个超级斐波拉契数列,前k个值为1,第n项是前n-1到n-k之和,输入k和q,q代表查询次数,接下来有q次输入,每次输入x,x代表查询第x项,输出答案,答案可能很大,因此要求输出对(10^9+7)取模这题考的时候想复杂了,半天没写出来,后来理清楚思路之后感觉也还好,但感觉还是挺多坑的,滑动窗口应该是最优时间复杂度吧。#include&nbsp;&lt;bits/stdc++.h&gt;using&nbsp;namespace&nbsp;std;const&nbsp;int&nbsp;MOD&nbsp;=&nbsp;1e9&nbsp;+&nbsp;7;//&nbsp;参数:滑动数组、窗口大小、淘汰指针、结果、目标项序号、当前序号int&nbsp;search(vector&lt;long&nbsp;long&gt;&amp;&nbsp;path,&nbsp;int&amp;&nbsp;k,&nbsp;int&amp;&nbsp;re,&nbsp;long&nbsp;long&amp;&nbsp;result,&nbsp;int&amp;&nbsp;x,&nbsp;int&amp;&nbsp;index){//&nbsp;[re]需要用之前的result更新,而result又需要用[re]更新,因此必须用一个临时变量操作int&nbsp;reval&nbsp;=&nbsp;path[re];&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//临时变量保留滑出的值,用于更新resultpath[re]&nbsp;=&nbsp;result;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//更新滑动窗口++re;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//更新滑动指针,并检测环if(re==k)re&nbsp;=&nbsp;0;++index;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//更新indexresult&nbsp;=&nbsp;(result*2&nbsp;-&nbsp;reval)&nbsp;%&nbsp;MOD;&nbsp;&nbsp;&nbsp;&nbsp;//更新第index项的值if&nbsp;(result&nbsp;&lt;&nbsp;0)&nbsp;result&nbsp;+=&nbsp;MOD;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;保证非负if(index==x)return&nbsp;result;return&nbsp;search(path,&nbsp;k,&nbsp;re,&nbsp;result,&nbsp;x,&nbsp;index);}int&nbsp;main(){int&nbsp;k;int&nbsp;q;cin&nbsp;&gt;&gt;&nbsp;k&nbsp;&gt;&gt;&nbsp;q;while(q--){int&nbsp;x;cin&nbsp;&gt;&gt;&nbsp;x;vector&lt;long&nbsp;long&gt;&nbsp;path(k,&nbsp;1);int&nbsp;re&nbsp;=&nbsp;0;long&nbsp;long&nbsp;result&nbsp;=&nbsp;k;index&nbsp;=&nbsp;k+1;if(x&lt;=k)cout&nbsp;&lt;&lt;&nbsp;1;else&nbsp;if(x==k+1)cout&nbsp;&lt;&lt;&nbsp;k;elsecout&nbsp;&lt;&lt;&nbsp;search(path,&nbsp;k,&nbsp;re,&nbsp;result,&nbsp;x,&nbsp;index);&nbsp;//从第k+1项开始才滑动if(q!=0)cout&nbsp;&lt;&lt;&nbsp;endl;}return&nbsp;0;}
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

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