Warning: session_start(): open(/tmp/sess_91d2898f871f45416c3172a2496ef60d, O_RDWR) failed: No space left on device (28) in /data/wiki/inc/init.php on line 239

Warning: session_start(): Failed to read session data: files (path: ) in /data/wiki/inc/init.php on line 239

Warning: Cannot modify header information - headers already sent by (output started at /data/wiki/inc/init.php:239) in /data/wiki/inc/auth.php on line 430

Warning: mkdir(): No space left on device in /data/wiki/lib/plugins/dw2pdf/vendor/mpdf/mpdf/src/Cache.php on line 19
Temporary files directory "/data/wiki/data/tmp/dwpdf/644/" is not writable

Warning: Cannot modify header information - headers already sent by (output started at /data/wiki/inc/init.php:239) in /data/wiki/inc/actions.php on line 38

Warning: Cannot modify header information - headers already sent by (output started at /data/wiki/inc/init.php:239) in /data/wiki/lib/tpl/dokuwiki/main.php on line 12
2020-2021:teams:namespace:裴蜀定理与一次不定方程 [CVBB ACM Team]

用户工具

站点工具


2020-2021:teams:namespace:裴蜀定理与一次不定方程

这是本文档旧的修订版!


考虑mod B = 0 · · ·B − 1 的最小能被表示的值是多少——大于他们的可以通过+kB 得到。假设这样的最小值分别为m0,m1, · · · ,mB−1,那么小于等于K 的能被表示的非负整数的数量是:

$$Σ^{B-1}_{i=0}⌊\frac{max(K - mi + B, 0)}{B}⌋$$

考虑如何求mi。由反证法可知0, A, · · · , (B − 1)A 在mod B 意义下必然互不相同,而这些数就枚举了mi。因此,当K < AB 时,上式化为:

$$ Σ_{i=0}^{⌊\frac{K}{A}⌋}⌊\frac{K - iA}{B}⌋$$

这是一个非常经典的直线下整点问题,使用类欧几里得算法可以在O(log max(A,B)) 的时间内求解。因此我们得到了计算小于等于K 的能被表示的非负整数的数量的工具,再二分一下就能解决原问题了。时间复杂度O(T log max(A,B) log min(K,AB)),可以通过A,B ≤ 1018, T ≤ 1000 的数据,也即本题原本的数据范围。

考虑到直线下整点是一个掏板子工作,因此放过了暴力。暴力可以这么写:假设A < B,我们尝试计算[kB, (k + 1)B) 这一段里有多少可以被表达出来的,那其实就是{(iA mod B) + kB|iA < (k + 1)B}的集合大小,枚举iA 计算确定答案在哪一段后,再在段内确定就好了——而段内有多少能被表达的已经被枚举了,打好标记for 一下就行了。时间复杂度O(T max(A,B))。

#include<stdio.h>
 
long long solve(long long n, long long a, long long b, long long m)
{
	if(b==0)
	{
		return n*(a/m);
	} 
	if(a>=m)
	{
		return n*(a/m)+solve(n,a%m,b,m);
	} 
	if(b>=m)
	{
		return (n-1)*n/2*(b/m)+solve(n,a,b%m,m);
	} 
	return solve((a+b*n)/m,(a+b*n)%m,m,b);
}
 
long long A,B,K;
 
void work()
{
	scanf("%lld%lld%lld",&A,&B,&K);
	long long l=1,r;
	r=(double)A*B>3e18?2e18+10:((long long)(2e18)+10<A*B-1?(long long)(2e18)+10:A*B-1);// double(A-1)*(B-1)/2>=K
	while(l<r)
	{
		long long mid=(l+r)/2;
		long long n=mid/A+1,m=B,a=mid-(n-1)*A+B,b=A;
		long long tot=solve(n,a,b,m)-1;
		long long cnt=mid-tot;
		if(cnt>=K)
		{
			r=mid;
		} 
		else
		{
			l=mid+1;
		} 
	}
	printf("%lld\n",l);
}
 
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		work();
	} 
}
2020-2021/teams/namespace/裴蜀定理与一次不定方程.1589203090.txt.gz · 最后更改: 2020/05/11 21:18 由 great_designer