裴蜀定理

基本式:ax+by=gcd(a,b)恒存在解。推论:\(\sum_{}^{}\)ai*gi=gcd(ai) 恒存在解。其中gi是方程的解,ai是系数。

【T4显然也是我出的】:给你n个点的图,还有m个数构成的集合{SI},对于图中的点|a-b|=Si的都存在边相连,求图中联通块个数。(n<=1e18,m<=2e5)

(1)当没有n的上界的限制,容易发现答案就是gcd(Si),对于有上界的限制,我们发现n的范围会导致辗转相减的时候会有某组联通的“路径”超过上界,导致出现无法联通的情况,所以考虑求出上界。假设Si<=m(m是未知的我要求的上界),假设当前凑出的数值是v,那么考虑v的变化范围,当v>=m,一定存在Si使得v-Si>=0,当v<=m-1,一定存在Si,v+SI<=2m-1,(SI<=m),也就是说如果要让Si定在一个范围内,在这个范围内凑出的数都是在“界”下凑出的,上界就是2m-1<=n,m<=n/2,上界是松的。

(2)接下来就是对({Si},n)问题规模的缩小。由(1)得知:

\(Si<=n/2\),求gcd可以得出部分Si凑出的联通块,那么我们用gcd记录这样的SI做出的贡献,这样的Si就可以删除了。

当全部\(Si>n/2\),一定存在“孤立点”,假设是pos,pos-min_Si<1,pos+min_Si>n,这样的pos一定是单独成块,对以后的Si合并没有任何影响,直接删除就行。cnt _pos=(n-min_SI)-(1+min_Si)+1=2*min_Si-n。所以直接把n-=cnt_pos,对于Si,我们也发现删除中间连续的cnt_pos块后相当于对Si的“跳跃”减去了cnt_pos的偏移量,所以Si-=cnt_pos,也是不影响答案的。因为min_Si>n/2,所以min_Si-cnt_pos=n-min_Si<=n/2,所以就是\(Si<=n/2\)的情况了

当我们把\(Si<=n/2\)的元素都删除,对于\(Si+gcd<=n\)的元素,我们发现Si是可以覆盖所有取模意义下的分组的,因为“gcd”的偏移量是可以出现在任意位置,而Si同样,相当于求解裴蜀定理基本式。对于这样的Si处理更新可以完全代表它的gcd,就可以愉快地删除了

对于\(Si+gcd>n\)的元素,Si满足\(Si+gcd>n,Si>n/2 ,n-Si>gcd\)也就是对于d<-->2d<-->3d<-->4*d....的点,Si一定不会对它们的联通产生影响(因为你把n看成数轴,Si看成连接数轴的一个“不可拉伸绳索”,绳索在n上移动,左端点和右端点的活动范围都在[1~d]<-->[n/d * d~n],所以中间的部分Si是“管不着”的,我们直接把n=d+n%d,对Si'=Si-(n-n')。把已经确定连通性的点消掉

子问题递归,边界是不存在Si+gcd>n。为了保证原分组条件被继承,在Si里加上gcd.

原版题解(理解了一晚上+一上午......)
image
image

【小凯的疑惑】给出(a,b),gcd(a,b)=1,求a,b不能凑出的最大整数

首先根据裴蜀定理ax+by=gcd(a,b)一定有解。考虑构造一个k,k是最大的-1后不合法的合法数。有
\(ax+by=k(x>=0,y>=0)\)那么对于k-1,如果也是合法的,假设x'是x最小非负整数解,y''是y最小非负整数解,那么对于k-1,一定有
a(x-x')+b(y-y')=k-1 或者
\(a(x-x'')+b(y-y'')=k-1\),原因很显然,因为考虑一组解使得k的变化波动尽量小,用k-这样的一个解,如果不是k-1,那一定不存在k-1使得能被凑出。我们考虑如果k-1不能被凑出,肯定是$(y-y'')<0 $ \((x-x'')<0\),或者说其中一个一定是凑出k-1的,那么只要都凑不出合法那一定是不合法

网上看到了一组结论,和小凯的疑惑一样的:

【1】对于\(ax+by=gcd(a,b)\)的最大不可解是\(a*b-a-b,x>=0,y>=0\)

【2】对于\(ax+by=gcd(a,b)\)的最大不可解是\(a*b,x>0,y>0\)

如果求\(a1*x1+a2*x2+a3*x3....=c\)的解是否存在(要求系数是>=0),不要死脑筋,\(O(n*m)\)的完全背包就可以解决。

这是给出a数组,求最少保留多少可以使得新数组可以凑出所有原数组可以凑出的数,就是把a集合里能用a表示的都删掉
const int N=2.5e4,M=110;
bool f[N];
int a[M];
int T,n;
int main()
{
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
	T=re();
	while(T--)
	{
		int n=re();
		_f(i,1,n)a[i]=re();
		sort(a+1,a+1+n);
		memset(f,0,sizeof(f));
		f[0]=1;int ans=n;
		_f(i,1,n)
		{
			if(f[a[i]])ans--;
			else
			{
				_f(j,a[i],a[n])f[j]|=f[j-a[i]];
			}
		}
		chu("%d\n",ans);
	}
    return 0;
}
posted on 2022-08-23 09:48  HZOI-曹蓉  阅读(114)  评论(0)    收藏  举报