0478 混合物
* * * *
拉格朗日计划
* * * *
混合物

考虑由A、B、C三种成份组成的混合物。每种混合物可以用所含A,B,C三种成份的比例即$(a : b : c)$来表示。

我们不能从混合物中分理出不同的成分,但可以通过组合不同数量的混合物来组成新的混合物。

例如,有三种混合物分别是$(3 : 0 : 2)$,$(3 : 6 : 11)$和$(3 : 3 : 4)$,把它们按$10:20:30$的比例混合后可得$(6 : 5 : 9)$,这是因为 $$(10\cdot\frac{3}{5}+20\cdot\frac{3}{20}+30\cdot\frac{3}{10}):(10\cdot\frac{0}{5}+20\cdot\frac{6}{20}+30\cdot\frac{3}{10}):(10\cdot\frac{2}{5}+20\cdot\frac{11}{20}+30\cdot\frac{4}{10})=18:15:27=6:5:9$$ 不过用这三种混合物无论怎样混合都无法配置出$(3 : 2 : 1)$,因为这三种混合物中B总是少于C。

给定$n\in\mathbb N$,令$M(n)=\{(a:b:c): 0\le a,b,c\le n, \gcd(a,b,c)=1\}$。

例如$M(2)$共包含19种混合物:(0 : 0 : 1), (0 : 1 : 0), (0 : 1 : 1), (0 : 1 : 2), (0 : 2 : 1), (1 : 0 : 0), (1 : 0 : 1), (1 : 0 : 2), (1 : 1 : 0), (1 : 1 : 1), (1 : 1 : 2), (1 : 2 : 0), (1 : 2 : 1), (1 : 2 : 2), (2 : 0 : 1), (2 : 1 : 0), (2 : 1 : 1), (2 : 1 : 2), (2 : 2 : 1)。

令$E(n)$为$M(n)$中能混合形成比例(1:1:1)的子集的数量。可以验证$E(1)=103, E(2)=520447, E(10) \bmod 11^8=82608406,E(500) \bmod 11^8=13801403$。

求$E(10^7) \bmod 11^8$。

本题难度:



解答

先通过 $$(a,b,c)\mapsto (\frac{a}{a+b+c}, \frac{b}{a+b+c}),$$ 把$(a,b,c)$映射为射影平面$\mathbb P^2$上的点,则三种混合物能混合出$(1,1,1)$当且仅当它们在$\mathbb P^2$上所形成的三角形中包含$(1/3,1/3)$,如此则本题转化为与第456题相同类型的问题。

最终结果是$59510340$。

注:因使用cache装饰器作记忆化搜索,以下代码为Python 3。

from functools import *
import math

n=10**7
mod=11**8

@cache
def Z(m):
    if m<=3:
        return (0,1,2,4)[m]
    j=math.isqrt(m)  
    res=m*(m+1)//2-sum(Z(m//i) for i in range(2,j+1))
    k=m//j
    while k>0:
        i=m//k
        res-=(i-j)*Z(k)
        j=i
        k-=1   
    return res

s=[1]*(n//2+2)
p=2
while p<=n//2:
    q=p
    while q<=n//2:
        s[q]=p
        q+=p
    p+=1
    while s[p]>1:
        p+=1

t=[1]*(n+2)
p=2
while p<=n:
    q=p
    while q<=n:
        t[q]*=(p-1)
        q+=p
    r=p*p
    while r<=n:
        q=r
        while q<=n:
            t[q]*=p
            q+=r
        r*=p   
    p+=1            
    while t[p]>1:
        p+=1

lines=[n+1-i for i in range(n+1)]
lines[1]=Z(n)
for i in range(2,n//2+1):
    k=i
    pos=[]
    neg=[]
    while k>1:
        p=s[k]
        while k%p==0:
            k//=p
        x=len(neg)
        neg.append(p)
        for q in pos:
            neg.append(p*q)
        for j in range(x):
            pos.append(p*neg[j])
        
    for d in range(2,n//i+1):
        r=n-d*i
        lines[d]+=r+sum(r//x for x in pos)-sum(r//x for x in neg)          

h=3*sum(lines[d]*t[d] for d in range(1,n+1))
a=pow(2,h,mod)
c=0
p=pow(2,h-lines[1],mod)
x=lines[1]
for d in range(1,n+1):
    y=lines[d]
    p=p*pow(2,x-y,mod)%mod
    c+=t[d]*(a-p)%mod  
    x=y     
print((pow(2,2*h+1,mod)-1-6*c)%mod)