每个数其实可以看成一个由二进制位组成的集合,那么第 i i i 个数表示的集合内肯定有一个二进制位是前 i − 1 i-1 i−1 个数的集合内所没有的。
于是有个结论,当 n > k n>k n>k 时,答案为 0 0 0。
设
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示前
i
i
i 个数字用
j
j
j 个二进制位的方案数,那么有:
f
[
i
]
[
j
]
=
∑
l
=
0
j
−
1
2
l
(
j
l
)
f
[
i
−
1
]
[
l
]
f
[
i
]
[
j
]
j
!
=
∑
i
=
0
j
−
1
f
[
i
−
1
]
[
l
]
2
l
l
!
×
1
(
j
−
l
)
!
\begin{aligned} f[i][j]&=\sum_{l=0}^{j-1} 2^l {j\choose l}f[i-1][l]\\ \frac {f[i][j]} {j!}&=\sum_{i=0}^{j-1} \frac {f[i-1][l]2^{l}} {l!} \times \frac 1 {(j-l)!} \end{aligned}
f[i][j]j!f[i][j]=l=0∑j−12l(lj)f[i−1][l]=i=0∑j−1l!f[i−1][l]2l×(j−l)!1
把中间的组合数拆开后,发现是个卷积的形式,用 F F T FFT FFT 加速一下后,时间复杂度为 O ( n k log k ) O(nk\log k) O(nklogk)。
拓展一下,这个方程还可以写成这样的形式:
f
[
x
+
y
]
[
i
]
=
∑
j
=
0
i
2
y
×
j
(
i
j
)
f
[
x
]
[
j
]
×
f
[
y
]
[
i
−
j
]
f
[
x
+
y
]
[
i
]
i
!
=
∑
j
=
0
i
f
[
x
]
[
j
]
×
2
y
×
j
j
!
×
f
[
y
]
[
i
−
j
]
(
i
−
j
)
!
\begin{aligned} f[x+y][i]&=\sum_{j=0}^i 2^{y\times j} {i\choose j} f[x][j]\times f[y][i-j]\\ \frac {f[x+y][i]} {i!}&=\sum_{j=0}^i \frac {f[x][j]\times 2^{y\times j}} {j!} \times \frac {f[y][i-j]} {(i-j)!} \end{aligned}
f[x+y][i]i!f[x+y][i]=j=0∑i2y×j(ji)f[x][j]×f[y][i−j]=j=0∑ij!f[x][j]×2y×j×(i−j)!f[y][i−j]
有了这个东西之后, f [ 2 n ] f[2n] f[2n] 可以直接从 f [ n ] f[n] f[n] 转移过来,于是倍增一下就能求出 f f f 了。
最后答案就是 ∑ i = 0 k C k i f [ n ] [ i ] \sum_{i=0}^k C_k^i f[n][i] ∑i=0kCkif[n][i]。
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 200010
#define mod 1000000007
#define ld long double
#define ll long long
#define bin(x) (1<<(x))
ll n;int k,F[maxn],G[maxn];
int inv[maxn],fac[maxn],inv_fac[maxn];
int ksm(int x,int y){int re=1;for(;(y&1?re=1ll*re*x%mod:0),y;y>>=1,x=1ll*x*x%mod);return re;}
void work()
{
inv[1]=1;for(int i=2;i<=maxn-10;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
fac[0]=inv_fac[0]=1;for(int i=1;i<=maxn-10;i++)fac[i]=1ll*fac[i-1]*i%mod;
inv_fac[maxn-10]=ksm(fac[maxn-10],mod-2);for(int i=maxn-11;i>=1;i--)inv_fac[i]=1ll*inv_fac[i+1]*(i+1)%mod;
}
int C(int x,int y){return 1ll*fac[x]*inv_fac[y]%mod*inv_fac[x-y]%mod;}
struct comp{
ld x,y;comp(ld xx=0,ld yy=0):x(xx),y(yy){}
comp operator +(const comp b){return comp(x+b.x,y+b.y);}
comp operator -(const comp b){return comp(x-b.x,y-b.y);}
comp operator *(const comp b){return comp(x*b.x-y*b.y,x*b.y+y*b.x);}
}a[maxn],b[maxn],dfta[maxn],dftb[maxn],dftc[maxn],dftd[maxn];
comp conj(comp x){return comp(x.x,-x.y);}
const ld Pi=acos(-1);
comp *w[30];void prep(int N,int lg_N){
for(int i=1;i<=lg_N;i++){
w[i]=new comp[bin(i-1)];w[i][0]=comp(1,0);comp wn(cos(Pi/bin(i-1)),sin(Pi/bin(i-1)));
for(int j=1;j<bin(i-1);j++)w[i][j]=w[i][j-1]*wn;
}
}
int limit=1,lg=0,r[maxn];void fft(comp *f)
{
for(int i=1;i<limit;i++)if(i<r[i])swap(f[i],f[r[i]]);
for(int mid=1,Lg=1;mid<limit;mid<<=1,Lg++)for(int j=0;j<limit;j+=(mid<<1))for(int i=0;i<mid;i++)
{comp t=f[j+i+mid]*w[Lg][i];f[j+i+mid]=f[j+i]-t;f[j+i]=f[j+i]+t;}
}
void FFT(int *f,int *g)
{
//注意,多次使用拆系数fft一定要加这个用来初始化的判断,我就是因为这个调了半天……
for(int i=0;i<limit;i++)if(i>k)a[i]=b[i]=comp(0,0);
else a[i]=comp(f[i]&32767,f[i]>>15),b[i]=comp(g[i]&32767,g[i]>>15);
fft(a);fft(b);for(int i=0;i<limit;i++)
{
static comp da,db,dc,dd;
int j=(limit-i)&(limit-1);
da=(a[i]+conj(a[j]))*comp(0.5,0);
db=(a[i]-conj(a[j]))*comp(0,-0.5);
dc=(b[i]+conj(b[j]))*comp(0.5,0);
dd=(b[i]-conj(b[j]))*comp(0,-0.5);
dfta[j]=da*dc;dftb[j]=da*dd;
dftc[j]=db*dc;dftd[j]=db*dd;
}
for(int i=0;i<limit;i++)a[i]=dfta[i]+dftb[i]*comp(0,1);
for(int i=0;i<limit;i++)b[i]=dftc[i]+dftd[i]*comp(0,1);
fft(a);fft(b);for(int i=0;i<2*k+1;i++)
{
int da=(ll)(a[i].x/limit+0.5)%mod;
int db=(ll)(a[i].y/limit+0.5)%mod;
int dc=(ll)(b[i].x/limit+0.5)%mod;
int dd=(ll)(b[i].y/limit+0.5)%mod;
f[i]=(da+((ll)(db+dc)<<15)%mod+((ll)dd<<30)%mod)%mod;
}
}
void solve(int ln)
{
if(ln==1){F[0]=0;for(int i=1;i<=k;i++)F[i]=1;return;}solve(ln>>1);
for(int i=1;i<=k;i++)F[i]=1ll*F[i]*inv_fac[i]%mod,G[i]=1ll*F[i]*ksm(2,1ll*(ln>>1)*i%(mod-1))%mod;
FFT(F,G);if(ln&1){for(int i=1;i<=k;i++)F[i]=1ll*F[i]*ksm(2,i)%mod,G[i]=inv_fac[i];FFT(F,G);}
for(int i=1;i<=k;i++)F[i]=1ll*F[i]*fac[i]%mod;
}
int main()
{
scanf("%lld %d",&n,&k);work();
if(n>k)return printf("0"),0;
while(limit<=2*k+2)limit<<=1,lg++;prep(limit,lg);
for(int i=1;i<limit;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(lg-1));
solve(n);int ans=0;
for(int i=1;i<=k;i++)ans=(ans+1ll*F[i]*C(k,i)%mod)%mod;
printf("%d",ans);
}