ограничение по времени на тест 2 секунды ограничен...
Created on: April 7, 2026
Answered using GPT-5.4 Thinking by Chat01
Created on: April 7, 2026
Answered using GPT-5.4 Thinking by Chat01
ограничение по времени на тест 2 секунды
ограничение по памяти на тест 256 мегабайт
Рассмотрим бинарные деревья, в которых у каждой вершины не более двух детей и каждая вершина помечена либо 0, либо 1.
За одну операцию можно инвертировать все метки на любом простом пути, проходящем через корень. Инвертировать метку означает заменить 0 на 1, а 1 на 0. Заметьте, что путь длины 1, содержащий только корень, тоже разрешён.
Стоимость такого бинарного дерева определяется как минимальное число операций, необходимое для того, чтобы сделать все метки в дереве равными 0.
Даны два целых числа 𝑛 и 𝑘. Посчитайте количество различных бинарных деревьев ровно с 𝑛 вершинами и стоимостью ровно 𝑘. Так как ответ может быть очень большим, выведите его по модулю 10^9+7.
Два бинарных дерева считаются различными, если у них различается структура, либо если структура одинакова, но хотя бы в одной вершине различаются метки.
Входные данные
Каждый тест состоит из нескольких наборов входных данных. В первой строке находится одно целое число 𝑡 (1≤𝑡≤10^4) — количество наборов входных данных. Далее следует описание наборов входных данных.
В единственной строке каждого набора входных данных содержатся два целых числа 𝑛 и 𝑘 (1≤𝑛≤10^6, 0≤𝑘≤𝑛).
Гарантируется, что сумма значений 𝑛 по всем наборам входных данных не превосходит 10^6.
Выходные данные
Для каждого набора входных данных выведите на отдельной строке одно целое число — количество помеченных бинарных деревьев с 𝑛 вершинами и стоимостью 𝑘 по модулю 10^9+7.
Пример
входные данныеСкопировать
6
2 0
2 1
1 1
7 6
69 67
314159 42
выходные данныеСкопировать
2
4
1
2016
382216284
559671824
Примечание
В первом наборе входных данных имеем 𝑛=2 и 𝑘=0. Существует два возможных дерева — корень с левым ребёнком и корень с правым ребёнком. Поскольку нужна стоимость 0, все вершины должны быть помечены 0. Следовательно, ответ равен 2.
Во втором наборе входных данных имеем 𝑛=2 и 𝑘=1. Таких деревьев 4. Допустимые помеченные деревья показаны на рисунке ниже:
В третьем наборе входных данных имеем 𝑛=1 и 𝑘=1. Существует только одно дерево — одна корневая вершина с меткой 1. Следовательно, ответ равен 1.
Реши на с++
I'm testing if A_nk follows a form involving Catalan numbers or powers of 2. I’ve noticed that for k=1, A_n1 seems to follow the pattern 4^(n-1). For k=2, the values grow rapidly, and I wonder if there's a binomial connection. Maybe I can derive a recurrence or check OEIS for hints.{0, 1}.
I’m trying to figure out if A[n,n] follows a pattern similar to Catalan numbers. The pattern I see seems to match twice the Catalan sequence for most values: 2 * Catalan_{n-1}. I’ll need to test this hypothesis more systematically and potentially derive it from generating functions and Lagrange’s formula.ves and binomial coefficients. I need to verify if this works for all k.bash -lc python3 - <<'PY' import sympy as s z=s.symbols('z') C=(1-s.sqrt(1-4z))/(2z) q=C-1 for k in [1,2,6]: S=lambda m: (1-q**(m+1))/s.sqrt(1-4z) if m>=0 else 0 T=s.expand(z(s.simplify(S(k)2 - S(k-2)2))) series=s.series(T,z,0,10) print('k',k,series) Tq=s.simplify((1+q)/(1-q)(2qk - q(2k-1)-q**(2k+1))) print('equal?', s.simplify(T-Tq)==0) PY
Revisiting recurrence formula and coefficients
Hmm, it seems like the series from T_k isn’t matching the data from brute force calculations. For k=1 and n=7, I got 2002 instead of 4096. When I check my T_k formula, it seems connected to a different sequence, maybe D(k) instead of A. I’ll revisit my recurrence, as my earlier formula seems off for A_nk. Let me recheck.
Aha, it seems the S1 formula is giving Catalans, not cumulative. The formula might be correct for the ratio, but I think I misspoke regarding the relationship between q and z C^2. The sum I used still needs some adjustments since the resulting series is off by one. Let's refine the derivation, especially for different values of m and n, to make sure we're counting correctly.
MOD=10**9+7
from functools import lru_cache
def cat(n):
import math
from math import comb
return comb(2n,n)//(n+1)
def A(n,k):
B=[[0](n+1) for _ in range(n+1)]
C=[[0]*(n+1) for _ in range(n+1)]
# B one-arm
B[0][0]=1
for m in range(1,n+1):
for i in range(m):
j=m-1-i
for a in range(i+1):
if B[i][a]==0: continue
for b in range(j+1):
if B[j][b]==0: continue
s=a+b
B[m][s]+=B[i][a]*B[j][b]
B[m][s+1]+=B[i][a]*B[j][b]
C[0][0]=1
for m in range(1,n+1):
for i in range(m):
j=m-1-i
for a in range(i+1):
if B[i][a]==0: continue
for b in range(j+1):
if B[j][b]==0: continue
t=max(a,b)
C[m][t]+=B[i][a]*B[j][b]
C[m][t+1]+=B[i][a]*B[j][b]
return C[n][k],B[n]
for n in range(1,8):
vals=[]
for k in range(n+1):
vals.append(A(n,k)[0])
print(n, vals, 'cat',cat(n), 'B?',A(n,min(n,0))[1][:n+1])
Нашёл удобную промежуточную модель.
Есть две похожие “стоимости”:
если можно инвертировать только путь от корня к одной вершине, это даёт очень простую биномиальную формулу;
исходная задача получается из неё через свёртку по левому и правому поддереву.
Сейчас дожимаю эту свёртку до закрытой формулы/быстрого DP.bash -lc python3 - <<'PY' from math import comb
def compute(nmax): B=[0 for _ in range(nmax+1)] A=[0 for _ in range(nmax+1)] B[0][0]=1 A[0][0]=1 for n in range(1,nmax+1): for i in range(n): j=n-1-i for a,v1 in enumerate(B[i]): if not v1: continue for b,v2 in enumerate(B[j]): if not v2: continue s=a+b B[n][s]+=v1v2 B[n][s+1]+=v1v2 t=max(a,b) A[n][t]+=v1v2 A[n][t+1]+=v1v2 return A,B A,B=compute(8) for n in range(1,8): print('n',n,'A',A[n][:n+1]) print('n',n,'B',B[n][:n+1]) PY
Simplifying generating function expression
I'm realizing the expression is a bit messy, but simplifying the square root gives a clearer form:
1
−
q
1
+
q
1+q
1−q
. Now, I'll substitute this back into the equation. For
a
≥
1
a≥1, the formula might involve a Catalan polynomial, so I'll simplify it manually to see if I can spot any patterns.bash -lc python3 - <<'PY' import sympy as s q,u=s.symbols('q u') z=q/(1+q)*2 srt=(1-q)/(1+q) H=(1-srts.sqrt(1-4qu/(1-q)**2))/(2q(1+u)/(1+q)**2) # maybe not exact
let's just substitute sqrt simplification in previous H
H=(1-((1-q)/(1+q))s.sqrt(1-4qu/(1-q)*2))/(2q(1+u)/(1+q)**2) H=s.simplify(H) print('H=',H) for a in range(5): Ea=s.simplify(s.series(H,u,0,a+1).removeO().coeff(u,a)) print('a',a, s.factor(Ea)) PY
Working on generating function and pattern recognition
So, I have this formula for
E
a
(
q
)
E
a
(q), with some expressions for small values of
a
a, but the polynomials might relate to Narayana/Catalan numbers — not sure if it's needed though. Let's focus on simplifying the inner sum and computing pair counts. I’ll look at generating functions
J
a
,
b
(
z
)
J
a,b
(z) and explore how to connect them to simpler forms with polynomials and powers of
(
1
+
q
)
(1+q) and
(
1
−
q
)
(1−q). Let me test a few small
k
k values for clues.bash -lc python3 - <<'PY' import sympy as s q,u=s.symbols('q u') z=q/(1+q)**2 H=(1-s.sqrt(1-4z(1+u)))/(2z(1+u)) for k in range(5): G=s.simplify(sum(s.series(H,u,0,k+1).removeO().coeff(u,a) for a in range(k+1))) print('k',k, s.factor(G)) PY
derive Gk by solving from known z-series maybe? Use H expansion but substitute sqrt=(1-q)/(1+q)
let's directly use formulas from E_a simplified and sum.
E=[1+q, q*(1+q)/(1-q), q2*(2-q)(1+q)/(1-q)3, q3(q2-4q+5)(1+q)/(1-q)**5] for k in range(4): G=sum(E[:k+1]) print('G',k,s.factor(s.together(G))) A2=s.simplify(q/(1+q)**2 * (G.subs(k,2) if False else 0)) PY
I’m considering deriving the generating function for
A
k
A
k
directly through Lagrange’s method or by interpreting labeled tree counts via Schröder/ballot numbers. I’ll try using recurrence on tree counts and an exact bivariate generating function to avoid needing a closed form for
G
k
G
k
. Let’s investigate further.
pythonfrom functools import cache @cache def all_shapes(n): if n==0:return [None] res=[] for i in range(n): for L in all_shapes(i): for R in all_shapes(n-1-i): res.append((L,R)) return tuple(res) def traverse(shape): arr=[] def dfs(s): if s is None:return None idx=len(arr); arr.append([None,None]) L,R=s li=dfs(L); ri=dfs(R) arr[idx]=[li,ri] return idx dfs(shape) return arr def ops(shape): tr=traverse(shape) n=len(tr) # vertices on left subtree and right subtree? parent=[-1]*n for i,(l,r) in enumerate(tr):
pythonfrom math import comb def rec(nmax): B=[[0]*(nmax+1) for _ in range(nmax+1)] A=[[0]*(nmax+1) for _ in range(nmax+1)] B[0][0]=1 A[0][0]=1 for n in range(1,nmax+1): for i in range(n): j=n-1-i for a in range(i+1): if not B[i][a]: continue for b in range(j+1): if not B[j][b]: continue s=a+b B[n][s]+=B[i][a]*B[j][b] B[n][s+1]+=B[i][a]*B[j][b] t=max(a,b) A[n][t]+=B[i][a]*B[j][b] A[n][t+1]+=B[i][a]*B[j][b] return A,B A,B=rec(
pythonimport sympy as s z=s.symbols('z') C=(1-s.sqrt(1-4*z))/(2*z) q=s.simplify(C-1) def S_formula(m): return (1-q**(m+1))/s.sqrt(1-4*z) for m in range(4): ser=s.series(S_formula(m), z, 0, 8).removeO() coeff=[s.expand(ser).coeff(z,n) for n in range(8)] print("m",m,coeff) coeff2=[] for n in range(8): coeff2.append(sum(s.binomial(n,a)*s.catalan(n) for a in range(m+1))) print(coeff2)
pythonA,B=rec(8) for n in range(1,8): print(n,A[n][:n+1])
pythonfrom math import comb for r in range(0,5): vals=[] for n in range(max(1,r),8): if n>=r: vals.append((n,A[n][n-r])) print("r",r,vals)
pythonimport sympy as s q,u=s.symbols('q u') z=q/(1+q)**2 H=s.simplify((1-s.sqrt(1-4*z*(1+u)))/(2*z*(1+u))) print(H) for a in range(6): Ea=s.simplify(s.expand(s.series(H,u,0,a+1).removeO()).coeff(u,a)) print(a,s.factor(s.together(Ea)))
pythonq,u=s.symbols('q u') z=q/(1+q)**2 H=s.simplify((1-s.sqrt(1-4*z*(1+u)))/(2*z*(1+u))) H=s.simplify(H.subs(s.sqrt((q-1)**2),1-q).subs(s.sqrt(q**2-2*q+1),1-q)) for a in range(6): Ea=s.simplify(s.expand(s.series(H,u,0,a+1).removeO()).coeff(u,a)) Ea=s.factor(s.together(Ea)) print(a,Ea)
pythonimport sympy as s q=s.symbols('q') z=q/(1+q)**2 # compute S_k as sum_n Catalan_n * prefix * z^n; then rewrite in q via series and maybe rational_interpolate def catalan(n): from math import comb return comb(2*n,n)//(n+1) for k in range(6): N=20 ser=sum(sum(s.binomial(n,a) for a in range(k+1))*catalan(n)*z**n for n in range(N)) # simplify rationally guess with denominator (1-q)**(2*k+1) expr=s.simplify(s.expand(ser)) # use sympy simplify to rational function maybe rat=s.apart(s.simplify(s.together(expr)),q) print("k",k, s.factor(s.together(s.simplify(expr))))
pythonfrom math import comb def cat(n): return comb(2*n,n)//(n+1) # series q(z) coefficients Catalan n>=1 N=20 qcoef=[0]+[cat(n) for n in range(1,N)] # q = sum_{n>=1} C_n z^n def series_add(a,b,N): c=[0]*N for i in range(N): c[i]=(a[i] if i<len(a) else 0)+(b[i] if i<len(b) else 0) return c def series_mul(a,b,N): c=[0]*N for i,x in enumerate(a): if x==0: continue for j,y in enumerate(b): if i+j>=N: break c[i+j]+=x*y return c def series_pow_one_minus_inv(exp,N): # (1-q)^(-exp) q=[0]*N for i in range(1,N): q[i]=cat(i) res=[0]*N; res[0]=1 # use binomial sum in q powers term=[0]*N; term[0]=1 for m in range(1,N): term=series_mul(term,q,N) coeff=comb(exp+m-1,m) for i in range(N): res[i]+=coeff*term[i] return res def q_series_of_poly(poly,N): # list coeff by q^d res=[0]*N; res[0]=poly[0] if poly else 0 q=[0]*N for i in range(1,N): q[i]=cat(i) powq=[[0]*N for _ in range(len(poly))] powq[0][0]=1 for d in range(1,len(poly)): powq[d]=series_mul(powq[d-1],q,N) for d,c in enumerate(poly): for i in range(N): res[i]+=c*powq[d][i] return res def conv_to_q_numerator(target,k,N=12): den=series_pow_one_minus_inv(2*k+1,N) # Find polynomial num of degree maybe k or 2k? maxdeg=2*k+2 # solve linear system using first maxdeg+1 coefficients import fractions, math # Build powers of q times den basis=[] q=[0]*N for i in range(1,N): q[i]=cat(i) cur=[0]*N; cur[0]=1 for d in range(maxdeg+1): basis.append(series_mul(cur,den,N)) cur=series_mul(cur,q,N) # solve by exact rationals using gaussian M=maxdeg+1 A=[[basis[d][n] for d in range(M)] for n in range(M)] b=[target[n] for n in range(M)] # gauss from fractions import Fraction A=[[Fraction(x) for x in row] for row in A]; b=[Fraction(x) for x in b] r=0 for c in range(M): piv=None for i in range(r,M): if A[i][c]: piv=i; break if piv is None: continue A[r],A[piv]=A[piv],A[r]; b[r],b[piv]=b[piv],b[r] fac=A[r][c] A[r]=[x/fac for x in A[r]]; b[r]/=fac for i in range(M): if i!=r and A[i][c]: fac=A[i][c] A[i]=[A[i][j]-fac*A[r][j] for j in range(M)] b[i]=b[i]-fac*b[r] r+=1 coeff=[b[i] for i in range(M)] return coeff for k in range(4): target=[sum(comb(n,a) for a in range(k+1))*cat(n) for n in range(10)] coeff=conv_to_q_numerator(target,k,12) print("k",k,coeff)
pythonimport sympy as s q=s.symbols('q') nums = { 0:[1,0,-1], 1:[1,-1,-1,1], 2:[1,-3,4,-1,-4,4,-1], 3:[1,-5,11,-7,-7,11,-5,1] } for k,arr in nums.items(): poly=sum(arr[i]*q**i for i in range(len(arr))) print(k,s.factor(poly))
pythonfrom math import comb def series_from_coeffs(coeffs,N): res=[0]*N for n,c in enumerate(coeffs[:N]): res[n]=c return res # compute z-series target for F_k def compute_A_prefix(k,N): arr=[0]*N for n in range(1,N): arr[n]=A[n][k] if n<len(A) and k<=n else 0 return arr # Need A bigger A,B=rec(20) def conv_to_q_rational(target,den_exp,N=15,maxdeg=None): if maxdeg is None:maxdeg=den_exp+4 den=series_pow_one_minus_inv(den_exp,N) q=[0]*N for i in range(1,N): q[i]=cat(i) basis=[] cur=[0]*N; cur[0]=1 for d in range(maxdeg+1): basis.append(series_mul(cur,den,N)) cur=series_mul(cur,q,N) M=maxdeg+1 # solve using first M equations from fractions import Fraction AA=[[Fraction(basis[d][n]) for d in range(M)] for n in range(M)] bb=[Fraction(target[n]) for n in range(M)] r=0 pivcols=[] for c in range(M): piv=None for i in range(r,M): if AA[i][c]: piv=i; break if piv is None: continue AA[r],AA[piv]=AA[piv],AA[r]; bb[r],bb[piv]=bb[piv],bb[r] fac=AA[r][c] AA[r]=[x/fac for x in AA[r]]; bb[r]/=fac for i in range(M): if i!=r and AA[i][c]: fac=AA[i][c] AA[i]=[AA[i][j]-fac*AA[r][j] for j in range(M)] bb[i]=bb[i]-fac*bb[r] pivcols.append(c) r+=1 coeff=[Fraction(0) for _ in range(M)] for i,c in enumerate(pivcols): coeff[c]=bb[i] return coeff for k in range(1,6): target=[0]+[A[n][k] for n in range(1,15)] # guess denominator (1-q)^(2k?) coeff=conv_to_q_rational(target,2*k+1,N=18,maxdeg=2*k+3) poly=sum(coeff[i]*q**i for i in range(len(coeff))) print("k",k, s.factor(poly))
python# test q-form guesses def q_to_z_coeff(expr,N=8): # expr sympy in q, substitute q series recursively? easiest numerically by z expression z=s.symbols('z') q_expr=(1-s.sqrt(1-4*z)-2*z)/(2*z) # maybe C-1 ser=s.series(s.simplify(expr.subs(q,q_expr)),z,0,N).removeO() return [s.expand(ser).coeff(z,n) for n in range(N)] for expr in [q**2*(1+q)*(2-q)/(1-q)**3, q**3*(1+q)*(5-4*q+q**2)/(1-q)**5]: print(q_to_z_coeff(expr,8))
pythonq=s.symbols('q') E0=1+q E1=q*(1+q)/(1-q) E2=q**2*(1+q)*(2-q)/(1-q)**3 for k,expr in [(1,E0+E1),(2,E0+E1+E2),(3,E0+E1+E2+q**3*(1+q)*(5-4*q+q**2)/(1-q)**5)]: print(k,s.factor(s.together(expr)))
pythonimport sympy as s z=s.symbols('z') qexpr=(1-s.sqrt(1-4*z)-2*z)/(2*z) def coeffs_from_q(expr,N=10): ser=s.series(s.simplify(expr.subs(q,qexpr)),z,0,N).removeO() return [s.expand(ser).coeff(z,n) for n in range(N)] for expr in [q**2*(2-q)/(1-q)**4, q**2*(2+q)/(1-q)**4, q**2*(1+q)/(1-q)**4, q**2*(1+q)**2/(1-q)**4]: print(expr, coeffs_from_q(expr,8))
pythonfrom math import comb def Aseq(k,N): return [0]+[A[n][k] if k<=n else 0 for n in range(1,N)] # Let's fit numerator degree maybe k+1 or 2k-1 for denom (1-q)^(2k) def fit_q(target,den_exp,maxdeg,N=20): den=series_pow_one_minus_inv(den_exp,N) qser=[0]*N for i in range(1,N): qser[i]=cat(i) basis=[] cur=[0]*N; cur[0]=1 for d in range(maxdeg+1): basis.append(series_mul(cur,den,N)) cur=series_mul(cur,qser,N) M=maxdeg+1 # least exact solve first M coeffs from fractions import Fraction AA=[[Fraction(basis[d][n]) for d in range(M)] for n in range(M)] bb=[Fraction
pythonfrom math import comb def rec(nmax): B=[[0]*(nmax+1) for _ in range(nmax+1)] A=[[0]*(nmax+1) for _ in range(nmax+1)] B[0][0]=1 A[0][0]=1 for n in range(1,nmax+1): for i in range(n): j=n-1-i for a in range(i+1): if not B[i][a]: continue for b in range(j+1): if not B[j][b]: continue val=B[i][a]*B[j][b] s=a+b B[n][s]+=val B[n][s+1]+=val t=max(a,b) A[n][t]+=val A[n][t+1]+=val return A,B A,B=rec(30) def cat(n): return comb(2*n,n)//(n+1) N=60 qcoef=[0]+[cat(n) for n in range(1,N)] # q(z) def mul(a,b,N): c=[0]*N for i,x in enumerate(a): if not x: continue for j,y in enumerate(b): if i+j>=N: break c[i+j]+=x*y return c def one_minus_inv(p,N): q=[0]*N for i in range(1,N): q[i]=cat(i) res=[0]*N; res[0]=1 term=[0]*N; term[0]=1 for m in range(1,N): term=mul(term,q,N) coeff=comb(p+m-1,m) for i in range(N): res[i]+=coeff*term[i] return res from fractions import Fraction def fit(target, den_exp, maxdeg, N=40): den=one_minus_inv(den_exp,N) q=[0]*N for i in range(1,N): q[i]=cat(i) basis=[] cur=[0]*N; cur[0]=1 for d in range(maxdeg+1): basis.append(mul(cur,den,N)) cur=mul(cur,q,N) M=maxdeg+1 AA=[[Fraction(basis[d][n]) for d in range(M)] for n in range(M)] bb=[Fraction(target[n]) for n in range(M)] r=0; piv=[] for c in range(M): pv=None for i in range(r,M): if AA[i][c]: pv=i; break if pv is None: continue AA[r],AA[pv]=AA[pv],AA[r]; bb[r],bb[pv]=bb[pv],bb[r] fac=AA[r][c] AA[r]=[x/fac for x in AA[r]]; bb[r]/=fac for i in range(M): if i!=r and AA[i][c]: fac=AA[i][c] AA[i]=[AA[i][j]-fac*AA[r][j] for j in range(M)] bb[i]=bb[i]-fac*bb[r] piv.append(c); r+=1 coeff=[Fraction(0) for _ in range(M)] for i,c in enumerate(piv): coeff[c]=bb[i] # verify out=[Fraction(0)]*N for d,c in enumerate(coeff): if not c: continue for n in range(N): out[n]+=c*basis[d][n] ok=all(out[n]==target[n] for n in range(min(N,len(target)))) return coeff,ok import sympy as s q=s.symbols('q') for k in range(1,8): target=[0]*40 for n in range(1,40): target[n]=A[n][k] if n<len(A) and k<=n else 0 found=False for den in range(2*k-1,2*k+4): for deg in range(k,3*k+4): coeff,ok=fit(target,den,deg,N=35) if ok: poly=sum(coeff[d]*q**d for d in range(len(coeff))) print("k",k,"den",den,"deg",deg,"poly",s.factor(poly)) found=True raise SystemExit print("no",k)
pythonfrom math import comb def cat(n): return comb(2*n,n)//(n+1) def T(n,a,b): s=0 for i in range(n+1): if i>=a and n-i>=b: s += cat(i)*cat(n-i)*comb(i,a)*comb(n-i,b) return s for a,b in [(0,0),(1,0),(1,1),(2,0),(2,1),(2,2)]: vals=[T(n,a,b) for n in range(max(a+b,0),10)] print((a,b),vals)
pythonfrom math import comb def cat(n): return comb(2*n,n)//(n+1) N=30 # series q(z) qser=[0]*N for n in range(1,N): qser[n]=cat(n) def mul(a,b): c=[0]*N for i,x in enumerate(a): if not x: continue for j,y in enumerate(b): if i+j>=N: break c[i+j]+=x*y return c def add(a,b,coef=1): c=a[:] for i in range(min(N,len(b))): c[i]+=coef*b[i] return c def pow_series(base,e): res=[0]*N; res[0]=1 cur=base[:] while e: if e&1: res=mul(res,cur) cur=mul(cur,cur); e//=2 return res def inv1mq(exp): # (1-q)^(-exp) res=[0]*N; res[0]=1 term=[0]*N; term[0]=1 for m in range(1,N): term=mul(term,qser) coeff=comb(exp+m-1,m) for i in range(N): res[i]+=coeff*term[i] return res # fit S_k numerator degree maybe k+1 with denom (1-q)^(2k-1), times (1+q) from fractions import Fraction def fit_S(k,deg): target=[sum(comb(n,a) for a in range(k+1))*cat(n) for n in range(N)] den=inv1mq(max(1,2*k-1)) oneplusq=[0]*N; oneplusq[0]=1 for i in range(1,N): oneplusq[i]=qser[i] den=mul(den, oneplusq) basis=[]; cur=[0]*N; cur[0]=1 for d in range(deg+1): basis.append(mul(cur,den)) cur=mul(cur,qser) M=deg+1 AA=[[Fraction(basis[d][n]) for d in range(M)] for n in range(M)] bb=[Fraction(target[n]) for n in range(M)] r=0;piv=[] for c in range(M): pv=None for i in range(r,M): if AA[i][c]: pv=i;break if pv is None: continue AA[r],AA[pv]=AA[pv],AA[r]; bb[r],bb[pv]=bb[pv],bb[r] fac=AA[r][c] AA[r]=[x/fac for x in AA[r]]; bb[r]/=fac for i in range(M): if i!=r and AA[i][c]: fac=AA[i][c] AA[i]=[AA[i][j]-fac*AA[r][j] for j in range(M)] bb[i]=bb[i]-fac*bb[r] piv.append(c); r+=1 coeff=[Fraction(0)]*(deg+1) for i,c in enumerate(piv): coeff[c]=bb[i] # verify all out=[Fraction(0)]*N for d,c in enumerate(coeff): if c==0: continue for n in range(N): out[n]+=c*basis[d][n] return coeff, all(out[n]==target[n] for n in range(N)), out for k in range(1,8): for deg in range(0,8): coeff,ok,out=fit_S(k,deg) if ok: print("k",k,"deg",deg,coeff) break
pythonA,B=rec(12) for n in range(3,8): for k in range(1,n): # solve maybe A[n][k]-4A[n-1][k]+? print(n,k,A[n][k],4*A[n-1][k], A[n-1][k-1], A[n-1][k+1] if k+1<=n-1 else None) print()
pythonfor n in range(2,8): row=[] for k in range(n+1): row.append(A[n][k]) print(n,row) print("normalize by 2^(n-k)") for n in range(2,8): print(n,[A[n][k]/(2**(n-k)) for k in range(n+1)])
pythonimport sympy as s n,k=s.symbols('n k', integer=True, nonnegative=True) # try guess for fixed k small as combination of binomial(n+r, s)*4^n and Catalan-like terms? # let's use sympy sequence_guess maybe for k=2 seq=[A[i][2] for i in range(2,15)] print(seq)
pythonfrom math import comb def rec(nmax): B=[[0]*(nmax+1) for _ in range(nmax+1)] A=[[0]*(nmax+1) for _ in range(nmax+1)] B[0][0]=1 for n in range(1,nmax+1): for i in range(n): j=n-1-i for a in range(i+1): if not B[i][a]: continue for b in range(j+1): if not B[j][b]: continue val=B[i][a]*B[j][b] s=a+b B[n][s]+=val B[n][s+1]+=val t=max(a,b) A[n][t]+=val A[n][t+1]+=val return A,B A,B=rec(25) seq=[A[i][2] for
pythonfrom math import comb def rec(nmax): B=[[0]*(nmax+1) for _ in range(nmax+1)] A=[[0]*(nmax+1) for _ in range(nmax+1)] B[0][0]=1 for n in range(1,nmax+1): for i in range(n): j=n-1-i for a in range(i+1): if not B[i][a]: continue for b in range(j+1): if not B[j][b]: continue val=B[i][a]*B[j][b] s=a+b B[n][s]+=val B[n][s+1]+=val t=max(a,b) A[n][t]+=val A[n][t+1]+=val return A,B A,B=rec(35) N=45 def cat(n): return comb(2*n,n)//(n+1) qser=[0]*N for i in range(1,N): qser[i]=cat(i) def mul(a,b): c=[0]*N for i,x in enumerate(a): if not x: continue for j,y in enumerate(b): if i+j>=N: break c[i+j]+=x*y return c def inv_factor(exp1, exp2): # (1-q)^-exp1 * (1+q)^-exp2 # 1/(1+q)^exp2 = sum (-1)^m C(exp2+m-1,m) q^m # build q powers res1=[0]*N; res1[0]=1 term=[0]*N; term[0]=1 for m in range(1,N): term=mul(term,qser) coeff=comb(exp1+m-1,m) for i in range(N): res1[i]+=coeff*term[i] if exp2==0: return res1 res2=[0]*N; res2[0]=1 term=[0]*N; term[0]=1 for m in range(1,N): term=mul(term,qser) coeff=(-1)**m * comb(exp2+m-1,m) for i in range(N): res2[i]+=coeff*term[i] return mul(res1,res2) from fractions import Fraction def fit_target(target, exp1, exp2, maxdeg): den=inv_factor(exp1,exp2) basis=[]; cur=[0]*N; cur[0]=1 for d in range(maxdeg+1): basis.append(mul(cur,den)) cur=mul(cur,qser) M=maxdeg+1 AA=[[Fraction(basis[d][n]) for d in range(M)] for n in range(M)] bb=[Fraction(target[n]) for n in range(M)] r=0;piv=[] for c in range(M): pv=None for i in range(r,M): if AA[i][c]: pv=i;break if pv is None: continue AA[r],AA[pv]=AA[pv],AA[r]; bb[r],bb[pv]=bb[pv],bb[r] fac=AA[r][c] AA[r]=[x/fac for x in AA[r]]; bb[r]/=fac for i in range(M): if i!=r and AA[i][c]: fac=AA[i][c] AA[i]=[AA[i][j]-fac*AA[r][j] for j in range(M)] bb[i]=bb[i]-fac*bb[r] piv.append(c); r+=1 coeff=[Fraction(0)]*(maxdeg+1) for i,c in enumerate(piv): coeff[c]=bb[i] out=[Fraction(0)]*N for d,c in enumerate(coeff): if not c: continue for n in range(N): out[n]+=c*basis[d][n] return all(out[n]==target[n] for n in range(N)), coeff for k in range(1,6): target=[0]*N for n in range(1,N): if n<len(A) and k<=n: target[n]=A[n][k] found=False for exp2 in range(0,4): for exp1 in range(2*k-2,2*k+4): for deg in range(k,3*k+5): ok,coeff=fit_target(target,exp1,exp2,deg) if ok: print("k",k,"exp1",exp1,"exp2",exp2,"deg",deg,coeff) found=True; raise SystemExit print("none",k)
pythonfrom math import comb def cat(n): return comb(2*n,n)//(n+1) # q series N=15 q=[0]*N for i in range(1,N): q[i]=cat(i) # 1-q one_minus=[0]*N; one_minus[0]=1 for i in range(1,N): one_minus[i]=-q[i] # x series z/(1-4z) x=[0]*N for i in range(1,N): x[i]=4**(i-1) def mul(a,b): c=[0]*N for i,xv in enumerate(a): for j,yv in enumerate(b): if i+j>=N: break c[i+j]+=xv*yv return c x2=mul(x,one_minus) print(x2[1:10])
python# coeffs of x^2(1-q) def pow_series(base,e): res=[0]*N; res[0]=1 cur=base[:] while e: if e&1: res=mul(res,cur) cur=mul(cur,cur); e//=2 return res coef=mul(pow_series(x,2),one_minus) print(coef[2:10])
pythonimport sympy as s z=s.symbols('z') expr=s.series((1-4*z)**(-s.Rational(3,2)),z,0,8).removeO() print([s.expand(expr).coeff(z,i) for i in range(8)]) expr2=s.series((1-4*z)**(-1),z,0,8).removeO() print([s.expand(expr2).coeff(z,i) for i in range(8)])
pythonfrom math import comb def cat(n): return comb(2*n,n)//(n+1) def formula(n,k): if k==0: return cat(n) ck=cat(k-1) ans=0 # square m=2*k-1 if m<=n: ans += ck*ck * (4**(n-m)) * comb(n-1,m-1) # same parity smaller j>=1 for j in range(k-2,0,-2): m=k+j-1 if m<=n: ans += 2*ck*cat(j-1) * (4**(n-m)) * comb(n-1,m-1) if k%2==0: r=n-k+1 if r>=0: half = comb(2*n,n-k+1) * 0 # placeholder # exact factorial formula half = comb(2*n, n) * comb(n, k-1) // comb(2*k-2, k-1) # maybe integer? # let's verify equivalence half2 = comb(2*n,n-k+1) * 0 special=(half - (4**(n-k+1))*comb(n-1,k-2))//2 ans += 2*ck*special return ans for n in range(1,12): for k in range(n+1): val=formula(n,k) if val!=A[n][k]: print("mismatch",n,k,val,A[n][k]) raise SystemExit print("all ok")
pythonMOD=10**9+7 def modpow(a,e): r=1 while e: if e&1:r=r*a%MOD a=a*a%MOD;e//=2 return r N=100 fact=[1]*(2*N+1) for i in range(1,2*N+1): fact[i]=fact[i-1]*i%MOD invfact=[1]*(2*N+1); invfact[-1]=pow(fact[-1],MOD-2,MOD) for i in range(2*N,0,-1): invfact[i-1]=invfact[i]*i%MOD pow4=[1]*(N+1) for i in range(1,N+1): pow4[i]=pow4[i-1]*4%MOD catm=[0]*(N+1) for i in range(N+1): catm[i]=fact[2*i]*invfact[i]%MOD*invfact[i]%MOD*pow(i+1,MOD-2,MOD)%MOD inv2=(MOD+1)//2 def C(n,r): if r<0 or r>n:return 0 return fact[n]*invfact[r]%MOD*invfact[n-r]%MOD def solve(n,k): if k==0:return catm[n] ck=catm[k-1] lim=min(k,n-k+1) start=1 if k%2 else 2 s=0 for j in range(start, lim+1, 2): m=k+j-1 s=(s + catm[j-1]*pow4[n-m]%MOD*C(n-1,m-1))%MOD ans=(2*ck*s - ck*ck%MOD*pow4[n-(2*k-1)]%MOD*C(n-1,2*k-2))%MOD if 2*k-1<=n else 2*ck*s%MOD if k%2==0: half = fact[2*n]*fact[k-1]%MOD*invfact[n]%MOD*invfact[2*k-2]%MOD*invfact[n-k+1]%MOD xprev = pow4[n-k+1]*C(n-1,k-2)%MOD special=(half - xprev)%MOD*inv2%MOD ans=(ans + 2*ck*special)%MOD return ans%MOD # compare A,B=rec(20) for n in range(1,15): for k in range(n+1): if solve(n,k)!=A[n][k]%MOD: print("bad",n,k,solve(n,k),A[n][k]); raise SystemExit print("all ok") print([solve(2,0),solve(2,1),solve(1,1),solve(7,6)])
Ниже — решение на C++ с выводом формулы за O(1) предусчёт + O(min(k, n-k+1)) на запрос.
Так как k <= n, а сумма всех n не больше 10^6, суммарная сложность O(10^6).
Для вершины v введём новую метку
где у отсутствующего ребёнка метка считается 0.
Это преобразование биективно: по всем b_v исходные a_v восстанавливаются снизу вверх.
Теперь важно следующее:
root -> x, то операция меняет ровно один b_x;t единицами среди b равно просто .Обозначим
где Cat_n — число форм бинарных деревьев из n вершин.
Если выбрать путь через корень:
b слева;b справа;b_root;b слева,b справа,b_root.Пусть в левом поддереве среди b ровно x единиц, в правом — y, а в корне b_root = c.
Тогда оптимально:
min(x,y) единиц слева и справа,Стоимость равна
Значит, для фиксированных x,y два возможных значения c дают стоимости:
max(x,y)max(x,y)+1ровно по одному разу.
Пусть
После подстановки
получается удобная формула, из которой после суммирования префиксов выводится
Остаётся взять коэффициенты.
k:то есть
Отсюда уже получается формула, которую можно считать за O(min(k,n-k+1)).
cpp#include <bits/stdc++.h> using namespace std; static const int MOD = 1000000007; long long mod_pow(long long a, long long e) { long long r = 1; while (e > 0) { if (e & 1) r = r * a % MOD; a = a * a % MOD; e >>= 1; } return r; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T; cin >> T; vector<pair<int,int>> qs(T); int maxN = 0; for (int i = 0; i < T; ++i) { int n, k; cin >> n >> k; qs[i] = {n, k}; maxN = max(maxN, n); } // factorials up to 2*maxN vector<long long> fact(2 * maxN + 1), invfact(2 * maxN + 1); fact[0] = 1; for (int i = 1; i <= 2 * maxN; ++i) fact[i] = fact[i - 1] * i % MOD; invfact[2 * maxN] = mod_pow(fact[2 * maxN], MOD - 2); for (int i = 2 * maxN; i >= 1; --i) invfact[i - 1] = invfact[i] * i % MOD; auto C = [&](int n, int r) -> long long { if (r < 0 || r > n) return 0; return fact[n] * invfact[r] % MOD * invfact[n - r] % MOD; }; // Catalan: Cat[n] = (2n)! / (n! (n+1)!) vector<long long> cat(maxN + 1); for (int n = 0; n <= maxN; ++n) { cat[n] = fact[2 * n] * invfact[n] % MOD * invfact[n + 1] % MOD; } vector<long long> pow4(maxN + 1, 1); for (int i = 1; i <= maxN; ++i) pow4[i] = pow4[i - 1] * 4 % MOD; const long long INV2 = (MOD + 1) / 2; auto coeff_x = [&](int n, int m) -> long long { // [z^n] (z/(1-4z))^m = 4^(n-m) * C(n-1, m-1) if (m < 1 || m > n) return 0; return pow4[n - m] * C(n - 1, m - 1) % MOD; }; auto coeff_special = [&](int n, int k) -> long long { // [z^n] x^k (1-q), only used for even k // = 1/2 * ( (2n)! (k-1)! / (n! (2k-2)! (n-k+1)!) // - 4^(n-k+1) * C(n-1, k-2) ) long long first = fact[2 * n]; first = first * fact[k - 1] % MOD; first = first * invfact[n] % MOD; first = first * invfact[2 * k - 2] % MOD; first = first * invfact[n - k + 1] % MOD; long long second = pow4[n - k + 1] * C(n - 1, k - 2) % MOD; long long res = (first - second) % MOD; if (res < 0) res += MOD; res = res * INV2 % MOD; return res; }; for (auto [n, k] : qs) { if (k == 0) { cout << cat[n] << '\n'; continue; } long long ck = cat[k - 1]; long long sum = 0; int start = (k & 1) ? 1 : 2; int lim = min(k, n - k + 1); for (int j = start; j <= lim; j += 2) { int m = k + j - 1; long long add = cat[j - 1] * coeff_x(n, m) % MOD; sum += add; if (sum >= MOD) sum -= MOD; } long long ans = 2LL * ck % MOD * sum % MOD; // j = k was counted with coefficient 2, but must be 1 if (2 * k - 1 <= n) { long long sq = ck * ck % MOD * coeff_x(n, 2 * k - 1) % MOD; ans -= sq; if (ans < 0) ans += MOD; } if ((k & 1) == 0) { long long sp = coeff_special(n, k); ans += 2LL * ck % MOD * sp % MOD; if (ans >= MOD) ans -= MOD; } cout << ans % MOD << '\n'; } return 0; }
Предобработка: O(maxN)
Один запрос: O(min(k, n-k+1))
Суммарно по всем тестам: O(sum n) ≤ O(10^6)
Если хочешь, я могу ещё отдельно расписать короткое “редакционное” доказательство формулы для F_k(z) без пропусков.