连分数 是实数作为有理数的特定收敛序列的表示。它们在算法竞赛(competitive programming)中很有用,因为它们易于计算,并且可以有效地用于在分母不超过给定值的所有数字中,找到基础实数(underlying real number)的最佳可能有理近似(best possible rational approximation)。
# return (x, y) such that Ax+By=C# assumes that such (x, y) existsdefdio(A,B,C):p,q=convergents(fraction(A,B))C//=A//p[-1]# divide by gcd(A, B)t=(-1)iflen(p)%2else1returnt*C*q[-2],-t*C*p[-2]
// returns [ah, ph, qh] such that points r[i]=(ph[i], qh[i]) constitute upper// convex hull of lattice points on 0 <= x <= N and 0 <= y <= r * x, where r =// [a0; a1, a2, ...] and there are ah[i]-1 integer points on the segment between// r[i] and r[i+1]autohull(autoa,intN){auto[p,q]=convergents(a);intt=N/q.back();vectorah={t};vectorph={0,t*p.back()};vectorqh={0,t*q.back()};
1 2 3 4 5 6 7 8 91011121314
for(int i = q.size() - 1; i >= 0; i--) {
if(i % 2) {
while(qh.back() + q[i - 1] <= N) {
t = (N - qh.back() - q[i - 1]) / q[i];
int dp = p[i - 1] + t * p[i];
int dq = q[i - 1] + t * q[i];
int k = (N - qh.back()) / dq;
ah.push_back(k);
ph.push_back(ph.back() + k * dp);
qh.push_back(qh.back() + k * dq);
}
}
}
return make_tuple(ah, ph, qh);
} ```
1 2 3 4 5 6 7 8 91011121314151617181920
# returns [ah, ph, qh] such that points r[i]=(ph[i], qh[i]) constitute upper convex hull# of lattice points on 0 <= x <= N and 0 <= y <= r * x, where r = [a0; a1, a2, ...]# and there are ah[i]-1 integer points on the segment between r[i] and r[i+1]defhull(a,N):p,q=convergents(a)t=N//q[-1]ah=[t]ph=[0,t*p[-1]]qh=[0,t*q[-1]]foriinreversed(range(len(q))):ifi%2==1:whileqh[-1]+q[i-1]<=N:t=(N-qh[-1]-q[i-1])//q[i]dp=p[i-1]+t*p[i]dq=q[i-1]+t*q[i]k=(N-qh[-1])//dqah.append(k)ph.append(ph[-1]+k*dp)qh.append(qh[-1]+k*dq)returnah,ph,qh
# (x, y) such that y = (A*x+B) // C,# Cy - Ax is max and 0 <= x <= N.defclosest(A,B,C,N):# y <= (A*x + B)/C <=> diff(x, y) <= Bdefdiff(x,y):returnC*y-A*xa=fraction(A,C)p,q=convergents(a)ph=[B//C]qh=[0]foriinrange(2,len(q)-1):ifi%2==0:whilediff(qh[-1]+q[i+1],ph[-1]+p[i+1])<=B:t=1+(diff(qh[-1]+q[i-1],ph[-1]+p[i-1])-B-1)//abs(diff(q[i],p[i]))dp=p[i-1]+t*p[i]dq=q[i-1]+t*q[i]k=(N-qh[-1])//dqifk==0:returnqh[-1],ph[-1]ifdiff(dq,dp)!=0:k=min(k,(B-diff(qh[-1],ph[-1]))//diff(dq,dp))qh.append(qh[-1]+k*dq)ph.append(ph[-1]+k*dp)returnqh[-1],ph[-1]
def solve(A, B, N): x, y = closest(A, N % A, B, N // A) return N // A - x, y ```
// sum floor(k * x) for k in [1, N] and x = [a0; a1, a2, ...]intsum_floor(autoa,intN){N++;auto[ah,ph,qh]=hull(a,N);
1 2 3 4 5 6 7 8 91011121314
// The number of lattice points within a vertical right trapezoid
// on points (0; 0) - (0; y1) - (dx; y2) - (dx; 0) that has
// a+1 integer points on the segment (0; y1) - (dx; y2).
auto picks = [](int y1, int y2, int dx, int a) {
int b = y1 + y2 + a + dx;
int A = (y1 + y2) * dx;
return (A - b + 2) / 2 + b - (y2 + 1);
};
int ans = 0;
for(size_t i = 1; i < qh.size(); i++) {
ans += picks(ph[i - 1], ph[i], qh[i] - qh[i - 1], ah[i - 1]);
}
return ans - N;
} ```
1234
# sum floor(k * x) for k in [1, N] and x = [a0; a1, a2, ...]defsum_floor(a,N):N+=1ah,ph,qh=hull(a,N)
1 2 3 4 5 6 7 8 9101112
# The number of lattice points within a vertical right trapezoid
# on points (0; 0) - (0; y1) - (dx; y2) - (dx; 0) that has
# a+1 integer points on the segment (0; y1) - (dx; y2).
def picks(y1, y2, dx, a):
b = y1 + y2 + a + dx
A = (y1 + y2) * dx
return (A - b + 2) // 2 + b - (y2 + 1)
ans = 0
for i in range(1, len(qh)):
ans += picks(ph[i-1], ph[i], qh[i]-qh[i-1], ah[i-1])
return ans - N
# find Q that minimizes Q*r mod m for 1 <= k <= n < m defmod_min(r,n,m):a=fraction(r,m)p,q=convergents(a)foriinrange(2,len(q)):ifi%2==1and(i+1==len(q)orq[i+1]>n):t=(n-q[i-1])//q[i]returnq[i-1]+t*q[i]