【4.13 提高班小记】单位根&&杂题

单位根

举例来说,我们想计算下面这个式子的值:

i(n2i) ∑ i ( n 2 i )

那么,我们构造二项式:

(1+x)n=i0(ni)xi ( 1 + x ) n = ∑ i ≥ 0 ( n i ) x i

带入 x=1 x = 1 x=1 x = − 1 ,我们得到:

2n=i0(ni)(11)n=i0(1)i(ni) 2 n = ∑ i ≥ 0 ( n i ) ( 1 − 1 ) n = ∑ i ≥ 0 ( − 1 ) i ( n i )

把这两个式子加起来:
2n=2i0(n2i) 2 n = 2 ∑ i ≥ 0 ( n 2 i )

由此可以得到:
i(n2i)=2n1 ∑ i ( n 2 i ) = 2 n − 1

那么,一个类似的问题就是,如果想计算:

i(n3i) ∑ i ( n 3 i )

应该怎么办呢?

在实数域上,你找不到一个和 +/- 1 有一样好的性质的数来帮你反演。

单位根

xn1=0 x n − 1 = 0 的解 w w 称为一个 n 次单位根。

对于一个单位根 w w ,如果 n 是使得 wn1=0 w n − 1 = 0 成立的最小正整数,那么 w w 称为一个 n 次本原单位根。

Remarks:如果在复平面上看,单位根均匀地分布在单位圆上,设第一象限第一个单位根为 w w ,那么其他的单位根都可以写为 wi 的形式。如果 (i,n)=d ( i , n ) = d ,那么 wi(n/d)=wn=1 w i ( n / d ) = w n = 1 ,而 n/d n / d 是比 n n 更小的一个正整数,所以 wi 不是n次本原单位根。

性质:

k,1ni=0n1wki=[n|k] ∀ k , 1 n ∑ i = 0 n − 1 w k i = [ n | k ]

证明:

如果 n|k n | k ,那么是 n n 个 1 加起来。

否则它是等比数列求和,值为:

1nwnkw0wk1=0

Remarks:当 n 是偶数的时候,这是 wi w i wi+n/2 w i + n / 2 相互消掉的过程。

回到上一个话题,想计算:

i0(n3i) ∑ i ≥ 0 ( n 3 i )

那么,令 w w 为一个 3 次本原多项式,构造多项式:
f(x)=(1+x)n

f(w)=i0(ni)wif(w2)=i0(ni)w2if(1)=i0(ni)w3i f ( w ) = ∑ i ≥ 0 ( n i ) w i f ( w 2 ) = ∑ i ≥ 0 ( n i ) w 2 i f ( 1 ) = ∑ i ≥ 0 ( n i ) w 3 i

考虑 f(1)+f(w)+f(w2) f ( 1 ) + f ( w ) + f ( w 2 ) ,我们发现,对于 (ni) ( n i ) 来说,它的系数是:

wi+w2i+w3i=3×[3|i] w i + w 2 i + w 3 i = 3 × [ 3 | i ]

所以, 13(f(1)+f(w)+f(w2))=ans 1 3 ( f ( 1 ) + f ( w ) + f ( w 2 ) ) = a n s .

大家应该注意到,这个算法扩展性很强:

任给一个生成函数 f(x) f ( x ) ,你想知道它的所有 k 倍数次项系数之和,可以转化为代入 k 个单位根,求平均值。

eg1 (bzoj 3328)

i0(nik)fibik ∑ i ≥ 0 ( n i k ) f i b i k

n 比较大,k 是几千左右,模数 P 下存在 k 次单位根。

单位根的求法:求出 P 的一个原根 g,g 可以认为是一个 P-1 次本原单位根, g(P1)/k g ( P − 1 ) / k 就是 k k 次本原单位根。

Sol

设 Fib 数的转移矩阵为 M,构造 (I+M)n ( I + M ) n ,其中 Mj M j 的系数恰好为 (nj)Mj ( n j ) M j ,(因为 I 和任意矩阵可交换,所以二项式定理适用)。把 Mj M j 中的左上角元素取出来就是 fibj f i b j .为了只算 k 倍数,令 f(x)=(I+xM)n f ( x ) = ( I + x M ) n ,然后带入单位根求值即可。

#include<cstdio>
#include<iostream>
using namespace std;
struct Ma{
    long long a[5][5];
};
int T,k,p,prime[10000],cnt;
long long n;
Ma x(Ma a,Ma b)
{
    Ma ans;
    for(int i=1;i<=2;i++)
        for(int j=1;j<=2;j++)
        {
            ans.a[i][j]=0;
            for(int k=1;k<=2;k++)
                ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j])%p;
        }
    return ans;
}
Ma M_Pow(Ma a,long long b)
{
    Ma ans=a,base=a;
    b--;
    while(b)
    {
        if(b&1) ans=x(ans,base);
        base=x(base,base);
        b>>=1;
    }
    return ans;
}
long long Pow(int a,int b)
{
    long long ans=1,base=a%p;
    while(b)
    {
        if(b&1) ans=ans*base%p;
        b>>=1;
        base=base*base%p;
    }
    return ans;
}
bool check(int g)
{
    for(int i=1;i<=cnt;i++)
        if(Pow(g,(p-1)/prime[i])==1) return false;
    return true;
}
int get_root(int p,int phi)
{
    for(int i=2;i<=phi;i++)
    {
        if(phi%i==0)
        {
            prime[++cnt]=i,phi/=i;
            while(phi%i==0) phi/=i;
        }
    }
    if(phi!=1) prime[++cnt]=phi;
    int g=2;
    while(g<p) 
    {
        if(check(g)) return g;
        g++;
    }
}
long long F(int x)
{
    Ma tmp;
    tmp.a[1][1]=tmp.a[1][2]=tmp.a[2][1]=x;
    tmp.a[2][2]=0;
    tmp.a[1][1]++,tmp.a[2][2]++;
    tmp=M_Pow(tmp,n);
    return (tmp.a[1][1]%p+p)%p;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        cnt=0;
        scanf("%lld%d%d",&n,&k,&p);
        int W=Pow(get_root(p,p-1),(p-1)/k);
        long long w=1,ans=0;
        for(int i=0;i<k;i++)
        {
            ans=(ans+F(w))%p;
            w=w*W%p;
        }
        ans=(ans*Pow(k,p-2)%p+p)%p;
        printf("%lld\n",ans);
    }
    return 0;
}

eg2

从 0 ~ (N-1) 中选出 K 个不同的数使得它们的和是 N 的倍数的方案数

K<=1000, N<=10^9, mod = 10^9+7

Sol

我们设:

f(x,y)=i=0n1(1+xiy) f ( x , y ) = ∏ i = 0 n − 1 ( 1 + x i y )

注意到 x 的次数记录了选的数的和,y 记录了个数。

问题相当于求 yk y k 项中,所有 n 倍数的 x 次幂 系数之和。

我们考虑用单位根反演它,带入单位根 w w :

f(w,y)=i=0n1(1+wiy)

w w 是一个 d 次本原单位根 (d|n)(这里 w 会取遍所有 n 的单位根,不一定是 n 次本原,设它是 d 次本原的)

f(w,y)=(i=0d1(1+wiy))n/d f ( w , y ) = ( ∏ i = 0 d − 1 ( 1 + w i y ) ) n / d

这里有这样一个式子成立:
i=0d1(xwi)=xd1 ∏ i = 0 d − 1 ( x − w i ) = x d − 1

证明:因为两边是两个 d 次多项式,并且零点/首项系数相同。

我们在两边乘上一个 wXXX w X X X ,可以得到 d1i=0(wix1)=xd1 ∏ i = 0 d − 1 ( w i x − 1 ) = x d − 1 ,把公式带回原式,得到:

f(w,y)=(+/yd+/1)n/d f ( w , y ) = ( + / − y d + / − 1 ) n / d

这时候算 yk y k 的系数就很容易了。

复杂度:我们只需要枚举所有 n n 的因子,有 ϕ(n/d) n n 次单位根是 d 次本原的。计算组合数可以暴力,复杂度很优秀。

EXT:选 K 个使得模 n 余 r 成立的方案数。

杂题

1 (51nod 1982)

考虑逐位确定,对给定的 N,从大到小枚举阶乘,然后试除,大概过程是:

for (int i = 100000; i >= 2; i--) {
    while (N % fact(i)) {
        N /= fact(i);
        ans.push(fact(i));
    }
}

注意到过程中没有加减法运算,那么我们可以用质因子分解来判整除。

我们把 1~N 里的所有质数取出来,设为 b1bk b 1 … b k ,设 n n 的形式为:

n=ibini

对于一个阶乘 x! x ! ,我们可以计算出每个质数在 x! x ! 的分解中的次数。

注意到这样一个事实:(x-1)! 相比于 x!,它只在 O(logx) O ( log ⁡ x ) 个质因子上次数发生了改变。

考虑线段树,我们对所有质数 b1bk b 1 … b k 建线段树,线段树每个位置存值:n 的质因子分解中 bi b i 的次数 ni n i x! x ! 的分解中 bi b i 的次数 xi x i ,以及 nixi ⌊ n i x i ⌋ 的值。

那么,计算 n 的分解中 x! x ! 出现了多少次,相当于询问 [ni/xi] [ n i / x i ] 的最小值。为了在 n n 中把 x! 除掉,我们暴力即可。当从 x! x ! (x1)! ( x − 1 ) ! 枚举的时候,暴力修改 logx log ⁡ x 个位置上的信息即可。

如果打标记,复杂度应该是 O(nlognloglogn) O ( n log ⁡ n log ⁡ log ⁡ n ) . 因为只有 x x 能整除 bi 才会修改,实际上和埃拉托斯特尼筛法复杂度一致。

2 (51nod 1325)

枚举一个根必选,然后建两个有根树,有根树上选儿子意味着选祖先,问题转化为最大权闭合图。

如果使用点分治,可以把枚举根的复杂度降一些。

3 (52nod 1355)

公式:

lcm(S)=Tgcd(T)1|T| l c m ( S ) = ∏ T g c d ( T ) − 1 | T |

它来源于:
max(S)=TS(1)|T|+1min|T| max ( S ) = ∑ T ⊆ S ( − 1 ) | T | + 1 min | T |

Fib 数又有一个公式:
gcd(fi,fj)=fgcd(i,j) gcd ( f i , f j ) = f gcd ( i , j )

那么我们所求即为:
TSf(1)|T|gcdT ∏ T ⊆ S f gcd T ( − 1 ) | T |

我们类比加法形式的:
TSf(gcdT)(1)T ∑ T ⊆ S f ( gcd T ) ( − 1 ) T

在加法形式中,这是经典的莫比乌斯反演问题,它的一系列推导手段都可以推广到乘法上。

反演套路:找到一个 g g 使得:

d|ng(d)=f(n)

那么:

=TSd|gcdTg(T)(1)|T|=dg(d)TSd(1)|T| = ∑ T ⊆ S ∑ d | gcd T g ( T ) ( − 1 ) | T | = ∑ d g ( d ) ∑ T ⊆ S d ( − 1 ) | T |

具体计算过程中,因为权值范围很小,正确实现的复杂度为 O(NlogN) O ( N log ⁡ N ) 即可通过。

4 (bzoj 4588)

我们把所有货币从小到大排序,那么它按照整除关系形成一个链。

我们考虑从前向后枚举每种硬币进行DP。

假设排好序的硬币序列是 vi v i , 不妨设 v1=1 v 1 = 1 .

我们设 fi(n) f i ( n ) 表示用 v1vi v 1 ∼ v i 拼出 n×vi n × v i 加上 Mmodvi M mod v i 的零散部分的方案数,那么:

f1(n)=1 f 1 ( n ) = 1

考虑从 1 1 2 的转移,首先我们知道 M M v2 的余数 r r 应该由 v1 提供,除此之外, v1 v 1 的使用次数应该是 d=v2/v1 d = v 2 / v 1 的整倍数,设:

g(n)=f1(dn+r) g ( n ) = f 1 ( d n + r )

枚举 v2 v 2 使用了多少个:
f2(n)=ing(i) f 2 ( n ) = ∑ i ≤ n g ( i )

然后我们使用归纳法可以证明 fi(n) f i ( n ) 是一个次数不超过 i i 的多项式,所以你只需要维护多项式的 (i+1) 个点值 / 系数表达 / 组合数表达 即可.

州阁筛

问题: 求 π(n), 它表示不超过 n n 的素数个数, n1010 .

考虑去 DP / 筛它,我们把不超过 n n 的素数取出来,设为 p1,p2pk p 1 , p 2 … p k .

fi(n) f i ( n ) 表示在 [1,n] [ 1 , n ] 中不被 p1pi p 1 ∼ p i 中任何一个整除的数的个数.

我们发现, fk(n)+k f k ( n ) + k 即为所求答案.

转移:

fk(n)=fk1(n)fk1(n/pk) f k ( n ) = f k − 1 ( n ) − f k − 1 ( ⌊ n / p k ⌋ )

首先用 p1 ~ p[k-1] 筛,然后用 pk 筛漏掉的.

一些数论常识告诉我们,dp的第二维有用的状态只有 n n 个.

直接使用这个算法进行dp,复杂度是 O(nlogn) O ( n log ⁡ n ) 并不能通过.

注意到:

n<pi+1 n < p i + 1 时,一定有 fi(n)=1 f i ( n ) = 1 .

n<(pi+1)2 n < ( p i + 1 ) 2 时, [n/pi+1]<pi+1 [ n / p i + 1 ] < p i + 1 ,所以转移式中 fi+1(n)=fi(n)fi([n/pi+1])=fi(n)1 f i + 1 ( n ) = f i ( n ) − f i ( [ n / p i + 1 ] ) = f i ( n ) − 1 ,发现转移的第二项是定值.

所以我们枚举到 pi p i 的时候,只需要关注 n>(pi)2 n > ( p i ) 2 的状态的转移, pin<(pi)2 p i ≤ n < ( p i ) 2 这些状态的转移可以打懒标记,最后统一处理.

加上这个优化,复杂度可以降到 O(n3/4logn) O ( n 3 / 4 log ⁡ n ) ,可以接受.

这是一个通用的算法,也适用于求关于素数的低阶多项式的和 (和,平方和…)

5 (51nod 1860)

问题相当于求 [a,b] 里有多少数可以由 <= P 的质数表示

进一步转化,相当于求 [1,a-1] 和 [1,b] 里由多少数可以这样表示.

如果一个数 n 可以由不超过 B 的数的乘积表示,称它为 B-smooth number ,B-光滑数

我们把 1~P 里的质数拿出来,设为 p1,p2,,pk p 1 , p 2 , … , p k .

我们设 fi(n) f i ( n ) 表示 [1,n] [ 1 , n ] 有多少数能表示为 p1,p2pi p 1 , p 2 … p i 的倍数,转移:

fi(n)=fi1(n)+fi([n/pi]) f i ( n ) = f i − 1 ( n ) + f i ( [ n / p i ] )

直接做的复杂度是 O(PN) O ( P N ) ,能优化吗?

从转移式中看不出一些好用的性质,考虑倒着 DP.

gi(n) g i ( n ) 表示 [1,n] [ 1 , n ] pi,pi+1pk p i , p i + 1 … p k 的乘积能表示的数的个数,转移:

gi(n)=gi+1(n)+gi([n/pi]) g i ( n ) = g i + 1 ( n ) + g i ( [ n / p i ] )

注意到:

n<pi n < p i 的时, gi(n)=1 g i ( n ) = 1 .

pin<(pi)2 p i ≤ n < ( p i ) 2 时, gi(n)=gi+1(n)+gi([n/pi])=gi+1(n)+1 g i ( n ) = g i + 1 ( n ) + g i ( [ n / p i ] ) = g i + 1 ( n ) + 1 .

发现了和例题中一样的性质,然后套路就行了.

Remark: 正着做的话,小质数很快的就能表示出区间里很多数,并且这些数的分布的规律可能并不好找. 倒着做的话,较大的质数表出的区间中的数比较稀疏,所以可以优化.


before

幂和

i=1nik ∑ i = 1 n i k
.

Sol
三方做法:

构造一个向量 A=(i0,i1,...ik,SUM). A = ( i 0 , i 1 , . . . i k , S U M ) .

(i+1)k=t=0k(kt)it. ( i + 1 ) k = ∑ t = 0 k ( k t ) i t .

发现可以通过 i0ik i 0 … i k 线性表示出 (i+1)k. ( i + 1 ) k .

所以可以构造转移矩阵

平方做法:

C(1, k) + C(2, k) + … + C(n, k) = C(n+1, k+1)

i=0n(ik) ∑ i = 0 n ( i k )

我们把 i^k 看作一个多项式,我们可以用 (i0)(ik) ( i 0 ) … ( i k ) 来表示这个多项式。(它的表示系数恰好是斯特林数)。

n log n 算法

斯特林数可以使用 FFT 来预处理

线性算法

我们可以猜想,答案是一个关于 n 的 k+1 次多项式。
( k 次多项式,给它求前缀和,可以得到一个 k+1 次多项式)。

给定一个 k 次多项式 f(x) 在 0 ~ k 处的取值 (a[0~k]),我们可以使用拉格朗日插值法,把这个多项式算出来。

代数上的知识:给定一个多项式在 k+1 个点的取值,可以唯一决定一个 k 次多项式,所以我们只需要构造多项式 f,使得 f(i) = a[i].

类比中国剩余定理的做法,我们考虑:

fi(x)=a[i]((x0)(x1)...(x(i1))(x(i+1))...(xk))/((i0)(i1)...(i(i1))(i(i+1))...(ik)) f i ( x ) = a [ i ] ∗ ( ( x − 0 ) ( x − 1 ) . . . ( x − ( i − 1 ) ) ( x − ( i + 1 ) ) . . . ( x − k ) ) / ( ( i − 0 ) ( i − 1 ) . . . ( i − ( i − 1 ) ) ( i − ( i + 1 ) ) . . . ( i − k ) )

它的分母相当于分子带入 x=i 得到的一个式子。
它的分子相当于在 (x-0)(x-1)…(x-k) 中把 (x-i) 一项去掉

ji,fi(j)=0(0<=j<=k)fi(i)=a[i] j ≠ i , f i ( j ) = 0 ( 0 <= j <= k ) f i ( i ) = a [ i ]

可以注意到这个 f_i(x) 是一个 k 次多项式(分子上乘了 k 个 x)

f(x)=fi(x) f ( x ) = ∑ f i ( x )

在很多场合,题目并不需要你去计算这个多项式的系数,而是要求你把某个 f(n) 算出来(已经给你 f(0) ~ f(k))的值。

考虑直接把 n 带入 fi(x) f i ( x ) 求值,然后加起来即可。

注意 42 ~ 44 行的式子:

  • 分母上是一个 (i-1)! 和一个 (k-i)! ,乘上若干个 -1 (O(1)算)。
  • 分子上的话,考虑在 O(k) 的时间内预处理 (n-0) ~ (n-k) 的前缀积,后缀积,那么对于一个 f_i(n) 来说,就是一个前缀积和后缀积的乘积(除掉了 n-i 这一项) O(1) 算

这整个式子可以在 O(k) 计算,从而得到 f(n) 的值。

应用到这个题上,我们可以在 O(k) 的时间内计算出 0^k, 1^k… k^k ,求前缀和得到这个多项式在 0 ~ k 上的取值,然后套算法即可。

总结:当你注意到题目中让你计数的对象是一个关于 n 的 k 次多项式,就可以考虑暴力算出多项式的前 k+1 项,然后套用这个算法。

CodePlus 3 T4

T 次询问,每次求长度为 N+M 的、恰好有 N 个 -1 和 M 个 1 的序列的前缀最小值的期望
N, M <= 200000, T <= 200000

Sol

总方案数是 C(N+M, M)

求一个随即变量 X 的期望,如果 X 的取值范围是整数,我们可以枚举 i,计算 Pr(X>i) 或者 Pr(X

BBQ Hard

给定长度为 N 的数组 A[] 和 B[]
ijC(Ai+Aj+Bi+Bj,Ai+Aj) ∑ i ∑ j C ( A i + A j + B i + B j , A i + A j )
N <= 200000, A[i], B[i] <= 2000

Sol

所求的每一项相当于从 (-A[i], -B[i]) 移动到 (A[j], B[j]) 的方案数(每一步向右或者上)。

因为 A[i], B[i] 都很小,所以可以直接做一个 4000 * 4000 的 DP。

AGC 019 F

有一个 N+M 的序列,每个位置是 0 或者 1,且恰好有 N 个 1
你需要依次猜每个位置的值,猜对得 1 分,否则不得分。
猜过一个位置,你会马上知道它的真实值
求最优策略下的得分期望
N+M <= 1e6

Sol

最优策略下,设到现在为止剩下 x 个 1 和 y 个 0,哪个多猜哪个是比较优秀的(得分概率为 max(x,y)/(x+y) m a x ( x , y ) / ( x + y ) )。

序列是随机生成的,所以你会转移到一个剩下 x 个 1 和 y 个 0 的局面的方案数为

(x+yx)×(Nx+MyNx)(N+MN) ( x + y x ) × ( N − x + M − y N − x ) ( N + M N )

答案为 xy(x+yx)×(Nx+MyNx)(N+MN)×max(x,y)x+y ∑ x ∑ y ( x + y x ) × ( N − x + M − y N − x ) ( N + M N ) × max ( x , y ) x + y ,但是这个式子的枚举量是 O(N^2) 的。

我们枚举 len=(x+y),计算倒数第 len 次猜的时候会得分的概率。

  • 定义一个局面(或者说一个状态)是被 0 支配的,当且仅当这 len 个数里 0 比 1 多(这时候,max(x,y) 中取 y)
  • 定义一个局面是被 1 支配的,当且仅当这 len 个数里 1 的个数大于等于 0(这时候,max(x,y) 中取 x)

我们从小到大枚举 len,从 len 到 len+1 的时候,绝大多数的序列被支配关系是不变的。

所以我们设几个变量,分别表示被 0 支配的序列的个数/产生的贡献和,被 1 支配的序列的个数/产生的贡献和。

从 len 转移到 len+1 的时候,只需要特殊处理被支配关系发生转变的序列(这一部分的计算不需要枚举任何东西,因为只有 0 和 1 的个数差不超过 1 的序列需要考虑)。

具体细节可以参见 AC 代码。

数论基础

  • 整数、同余、最大公约数与最小公倍数
  • 裴蜀定理,一次不定方程,中国剩余定理
裴蜀定理

形如 ax+by = c 的方程称为二元一次不定方程。

不定方程:限定了未知数只能取整数。

使得 ax+by=d 有解的、最小的正整数 d 恰好是 gcd(a,b)。
这里 x 和 y 是未知数。

ax+by=gcd(a,b) 一定有解,它的解可以通过扩展欧几里得算法找出来。

HAOI 外星人

Sol

对于一个 N,求欧拉函数 phi(N) 的过程:

  • 令 ans = N
  • 枚举 N 的每种质因子 p,令 ans = ans / p * (p - 1)

注意到:

  • 对于 N 的一个质因子 p > 2,ans / p * (p - 1) 虽然消掉了一个 p,但是带来了几个更小的质因子。这个过程会持续下去,直到变成一个 2,然后 ans / 2 可以消掉一个质因子 2 而不产生任何新的质因子。
  • 除了 N 是奇数的第一次取 phi,每一次一定会消掉一个 2。

所以我们只需要数一下有多少个 2 需要消掉即可。

威尔逊定理

我们从多项式的观点看,费马小定理告诉我们:

1xP1,xP110(modP) ∀ 1 ≤ x ≤ P − 1 , x P − 1 − 1 ≡ 0 ( mod P )

那么我们知道, 1P1 1 ∼ P − 1 都是 xP11 x P − 1 − 1 的根(在 mod P 下)。又因为 xP11 x P − 1 − 1 是一个首项为 1 的 P-1 次多项式,所以有:
xP11(x1)(x2)(xP+1)(modP) x P − 1 − 1 ≡ ( x − 1 ) ( x − 2 ) … ( x − P + 1 ) ( mod P )

比较两个多项式的系数,由此得到威尔逊定理:

(P1)!1(modP) ( P − 1 ) ! ≡ − 1 ( mod P )

另外一个结论:对于一个给定的质数 P P ,我们定义 f(k) 表示从 1P1 1 ∼ P − 1 中选 k k 个不同的数求乘积,所有选法的乘积之和(在模 P 意义下)那么有:
f(P1)=1(modP)1i<P1,f(i)0(modP)

证明:考虑 1iP1(xi) ∏ 1 ≤ i ≤ P − 1 ( x − i ) k k 次项系数。

CC Feb / Jan

给定N,定义 f(K) 为从 [1,N] 中选K个不同的整数求乘积,不同的选法的乘积之和

给定R,求 [1,R] 中有多少f(K)是给定质数P的倍数

Sol

问题相当于求 1iN(xi) [1,R] [ 1 , R ] 中有多少项为 0(或者说有多少项非 0)。

N=aP+b N = a P + b ,那么原式可以写为:

xa(1iP1(xi))a1ib(xi) x a ( ∏ 1 ≤ i ≤ P − 1 ( x − i ) ) a ∏ 1 ≤ i ≤ b ( x − i )

因为 1iP1(xi) ∏ 1 ≤ i ≤ P − 1 ( x − i ) 等于 xP11 x P − 1 − 1 ,所以上式可以写成:
xa(xP11)a1ib(xi) x a ( x P − 1 − 1 ) a ∏ 1 ≤ i ≤ b ( x − i )

不妨设 b<P1 b < P − 1 ,否则右边又能凑出一个 xP11 x P − 1 − 1

注意到上式左边只有 P1 P − 1 的整倍数有值,而右边是一个次数为 b<P1 b < P − 1 的多项式,所以右边乘到左边相当于把左边每个系数“复制”了若干份。

右边的多项式可以使用分治 FFT 展开计算,左边的式子可以用 Lucas 定理统计有多少非 0 项,然后两边结合即可。

Catalan 数

Catalan 数定义:满足递推公式

h0=1hn=0i<nhihni1 h 0 = 1 h n = ∑ 0 ≤ i < n h i ⋅ h n − i − 1

的数列 {hn} { h n }

推导方法

生成函数方法

设它的生成函数为 C(x) C ( x ) ,它满足:

C(x)=xC(x)2+1 C ( x ) = x C ( x ) 2 + 1

解得:
C(x)=114x2x C ( x ) = 1 − 1 − 4 x 2 x

使用二项式定理展开 14x 1 − 4 x
(14x)12=i(4x)i×(1/2i)=(4x)i×1i!×(1/2)(1/2)(3/2)(1)(2) (1) ( 1 − 4 x ) 1 2 = ∑ i ( − 4 x ) i × ( 1 / 2 i ) (2) = ( − 4 x ) i × 1 i ! × ( 1 / 2 ) ∗ ( − 1 / 2 ) ∗ ( − 3 / 2 ) …

思路: 4i 4 i 拆成 2i×2i 2 i × 2 i ,一个 2i 2 i 消掉之后分母上所有 2,一个 2i 2 i 展开成 (2n)!!n! ( 2 n ) ! ! n ! (2/1 * 4/2 * 6/3 …),从而我们可以在分子分母上构造出来 (2nn) ( 2 n n ) ,注意到前面有 i i 个 -1,之后又有 i1 个 -1,放在一起以后每一项都是负的。

组合方法

(2nn)(2nn1) ( 2 n n ) − ( 2 n n − 1 )

组合意义
  • N 条边的凸多边形三角剖分方案数
  • N 个点的二叉树的形态数
  • N 对括号的合法括号序列数
  • 1~N 依次入栈,可能的出栈序列数
两种形式
  • 维护了一个计数器,每次给他加一或者减一,不能为负/低于某个值,这一类问题常常可以用括号序计数的角度思考
  • 对一个规模为N的问题计数,它可以拆成两个规模为x和 N-x-1的问题,这一类问题常可用二叉树形态计数的角度思考,配合生成函数的卷积。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值