Time Limit 2s
Memory Limit 512M
Description
从1到n中选k个互不相同的,问一起为边长能组成凸k边形的方案数
Input
一行,n,k
Output
一行答案对998244353取模
Sample
Input1
100 3
Output1
79625
Input2
100 4
Output2
3281225
Input3
100 5
Output3
72464552
Data Constraint
n
≤
1
0
9
,
k
≤
200
n\leq 10^9,k\leq 200
n≤109,k≤200
什么凸多边形。。。搞得很难的样子,就是求选取方案种数使得最小的k-1个数的和大于第k个
考虑
O
(
n
k
)
O(nk)
O(nk)怎么做
A
n
s
=
(
n
k
)
−
∑
i
=
1
n
(
n
−
i
+
1
)
f
i
,
k
−
1
Ans={n\choose k}-\sum_{i=1}^n (n-i+1)f_{i,k-1}
Ans=(kn)−∑i=1n(n−i+1)fi,k−1(最大的数>=除最大数的和=i)
f
i
,
j
f_{i,j}
fi,j表示选j个拼i的方案数
假设选出来的
a
1
<
a
2
<
⋯
<
a
k
a_1<a_2<\cdots<a_k
a1<a2<⋯<ak
其差分
d
1
,
d
2
,
⋯
 
,
d
k
>
0
d_1,d_2,\cdots,d_k>0
d1,d2,⋯,dk>0
那么
(
k
−
1
)
d
1
+
(
k
−
2
)
d
2
+
⋯
+
d
k
−
1
=
i
(k-1)d_1+(k-2)d_2+\cdots+d_{k-1}=i
(k−1)d1+(k−2)d2+⋯+dk−1=i
因此这可以背包
考虑生成函数
f
i
,
k
−
1
=
[
x
i
]
∏
i
=
1
k
−
1
x
i
1
−
x
i
f_{i,k-1}=[x^i]\prod_{i=1}^{k-1}\frac{x^i}{1-x^i}
fi,k−1=[xi]∏i=1k−11−xixi
因为
i
d
(
i
)
=
i
+
1
id(i)=i+1
id(i)=i+1的OGF是
1
(
1
−
x
)
2
\frac 1{(1-x)^2}
(1−x)21
∑
i
=
1
n
(
n
−
i
+
1
)
f
i
,
k
−
1
\sum_{i=1}^n (n-i+1)f_{i,k-1}
∑i=1n(n−i+1)fi,k−1是个卷积
(
n
k
)
−
A
n
s
=
[
x
n
]
[
1
(
1
−
x
)
2
∏
i
=
1
k
−
1
x
i
1
−
x
i
]
=
[
x
n
−
1
2
k
(
k
−
1
)
]
[
1
(
1
−
x
)
2
∏
i
=
1
k
−
1
1
−
x
i
]
{n\choose k}-Ans=[x^n][\frac1{(1-x)^2}\prod_{i=1}^{k-1}\frac{x^i}{1-x^i}]=[x^{n-\frac12k(k-1)}][\frac1{(1-x)^2\prod_{i=1}^{k-1}1-x^i}]
(kn)−Ans=[xn][(1−x)21∏i=1k−11−xixi]=[xn−21k(k−1)][(1−x)2∏i=1k−11−xi1]
设
m
=
n
−
1
2
k
(
k
−
1
)
m=n-\frac12k(k-1)
m=n−21k(k−1)
我们发现下面的
(
1
−
x
)
2
∏
i
=
1
k
−
1
1
−
x
i
(1-x)^2\prod_{i=1}^{k-1}1-x^i
(1−x)2∏i=1k−11−xi可以表示成
1
−
G
(
x
)
1-G(x)
1−G(x)的形式
这样就可以用线性常系数齐次递推,设
(
n
k
)
−
A
n
s
=
F
(
x
)
=
1
1
−
G
(
x
)
{n\choose k}-Ans=F(x)=\frac 1{1-G(x)}
(kn)−Ans=F(x)=1−G(x)1
G
(
x
)
G(x)
G(x)的最高次项为
x
t
x^t
xt
那么
F
(
x
)
G
(
x
)
=
F
(
x
)
−
1
F(x)G(x)=F(x)-1
F(x)G(x)=F(x)−1
又G(x)常数项为0,那么设
{
f
n
}
\{f_n\}
{fn}为F(x)的系数数列,
{
g
n
}
\{g_n\}
{gn}同理,有
f
n
=
∑
i
=
1
n
f
n
−
i
g
i
f_n=\sum_{i=1}^n f_{n-i}g_i
fn=∑i=1nfn−igi,这可以看做一个递推
设关于F(x)的矩阵
A
A
A
A
=
[
f
1
f
2
⋮
f
t
]
A= \begin{bmatrix} f_1\\ f_2\\ \vdots\\ f_t\\ \end{bmatrix}
A=⎣⎢⎢⎢⎡f1f2⋮ft⎦⎥⎥⎥⎤
设其转移矩阵为
T
T
T
T
=
[
g
1
g
2
⋯
g
t
−
1
g
t
1
0
⋯
0
0
0
1
⋯
0
0
⋮
⋮
⋱
⋮
⋮
0
0
⋯
1
0
]
T= \begin{bmatrix} g_1 & g_2 & \cdots & g_{t-1} & g_t\\ 1 & 0 & \cdots & 0 & 0 \\ 0 & 1 & \cdots & 0 & 0\\ \vdots & \vdots & \ddots & \vdots & \vdots\\ 0 & 0 & \cdots & 1 & 0\\ \end{bmatrix}
T=⎣⎢⎢⎢⎢⎢⎡g110⋮0g201⋮0⋯⋯⋯⋱⋯gt−100⋮1gt00⋮0⎦⎥⎥⎥⎥⎥⎤
那么要求的
f
m
f_m
fm可以通过求
A
T
m
−
t
AT^{m-t}
ATm−t得
假设我们要求
T
m
T^m
Tm
但是t很大,m也很大
有一个叫做凯莱·哈密顿定理的东西
T的特征多项式
r
(
λ
)
=
det
(
λ
I
−
T
)
r(\lambda)=\det(\lambda I-T)
r(λ)=det(λI−T)
则
r
(
T
)
=
0
r(T)=0
r(T)=0
特殊的,对于上面这类型的矩阵,其特征多项式为
r
(
x
)
=
x
t
−
∑
i
=
1
t
g
i
x
t
−
i
i
r(x)=x^t-\sum_{i=1}^tg_ix^{t-i}i
r(x)=xt−∑i=1tgixt−ii
r
(
x
)
r(x)
r(x)只有t项!
如果求出
x
m
m
o
d
  
r
(
x
)
x^m\mod r(x)
xmmodr(x)再把T带进去就可以把指数大大缩小
这个可以倍增+多项式取模求
假设已经求出了
h
(
x
)
=
x
m
m
o
d
  
r
(
x
)
h(x)=x^m\mod r(x)
h(x)=xmmodr(x)
但是t很大怎么办
考虑回原式子,我们需要求的是
[
A
h
(
T
)
]
[
n
]
[Ah(T)][n]
[Ah(T)][n]
又有
f
t
+
i
=
(
A
T
i
)
[
n
]
f_{t+i}=(AT^i)[n]
ft+i=(ATi)[n]
这样就只用求
∑
f
t
+
i
[
x
i
]
h
(
x
)
\sum f_{t+i}[x^i]h(x)
∑ft+i[xi]h(x)即可
只用求逆弄出f的前2t位,取模搞出个
h
(
x
)
h(x)
h(x)就可以求答案了
多项式取模(求商)
设
∣
f
(
x
)
∣
|f(x)|
∣f(x)∣表示
f
(
x
)
f(x)
f(x)的最高次数
假设要求
A
(
x
)
m
o
d
  
B
(
x
)
A(x)\mod B(x)
A(x)modB(x)
A
(
x
)
=
B
(
x
)
C
(
x
)
+
D
(
x
)
A(x)=B(x)C(x)+D(x)
A(x)=B(x)C(x)+D(x),且
∣
D
(
x
)
∣
<
∣
B
(
x
)
∣
|D(x)|<|B(x)|
∣D(x)∣<∣B(x)∣
设
∣
A
(
x
)
∣
=
n
,
∣
B
(
x
)
∣
=
m
|A(x)|=n,|B(x)|=m
∣A(x)∣=n,∣B(x)∣=m
有
A
(
1
x
)
=
B
(
1
x
)
C
(
1
x
)
+
D
(
1
x
)
A(\frac1x)=B(\frac1x)C(\frac1x)+D(\frac1x)
A(x1)=B(x1)C(x1)+D(x1)
同时乘上
x
n
x^n
xn
x
n
A
(
x
)
=
x
m
B
(
x
)
×
x
n
−
m
C
(
x
)
+
x
n
D
(
x
)
x^nA(x)=x^mB(x)\times x^{n-m}C(x)+x^nD(x)
xnA(x)=xmB(x)×xn−mC(x)+xnD(x)
x
n
A
(
x
)
,
x
m
B
(
x
)
,
x
n
−
m
C
(
x
)
x^nA(x),x^mB(x),x^{n-m}C(x)
xnA(x),xmB(x),xn−mC(x)都相当于将他们反过来
只有
D
(
x
)
D(x)
D(x)的前n-m项系数都是0,
两边同时
m
o
d
  
x
n
−
m
\mod x^{n-m}
modxn−m
消去
D
′
(
x
)
D'(x)
D′(x)(这里用“
′
'
′”表示将其反过来的多项式)变为
A
′
(
x
)
=
B
′
(
x
)
C
′
(
x
)
(
m
o
d
  
x
n
−
m
)
A'(x)=B'(x)C'(x)(\mod x^{n-m})
A′(x)=B′(x)C′(x)(modxn−m)
C
′
(
x
)
=
A
′
(
x
)
B
′
(
x
)
m
o
d
  
x
n
−
m
C'(x)=\frac{A'(x)}{B'(x)}\mod x^{n-m}
C′(x)=B′(x)A′(x)modxn−m用一个多项式求逆
然后再乘回去求出
D
(
x
)
D(x)
D(x)
#include<cstring>
#include<cstdio>
#include<algorithm>
#define mo 998244353
#define K 262144
#define ll long long
#define REP(i,a,b) for(int i=a,___=b;i<___;++i)
#define RED(i,a,b) for(int i=a,___=b;--i>=___;)
using namespace std;
int N,k,G[K],F[K],t,w[K],rev[K],D[K];
ll n,m;
ll qpow(ll a,ll i){
ll r=1;for(;i;i>>=1,a=a*a%mo)if(i&1)r=r*a%mo;return r;
}
void adjust(int &N,int l){
for(;N<l;N<<=1);for(;N>>1>=l;N>>=1);
}
void prep(){
ll W=qpow(3,(mo-1)/K);w[0]=1;REP(i,1,K)w[i]=W*w[i-1]%mo;
}
void ntt(int *a){
REP(i,1,N){
rev[i]=(rev[i>>1]>>1)+(i&1)*(N>>1);
if(rev[i]<i)swap(a[i],a[rev[i]]);
}ll T;
for(int h=1,m=2,g=1;h<N;h=m,m<<=1,g++)REP(i,0,h)for(int j=i,k;j<N;j+=m)
T=1ll*w[(K>>g)*i]*a[k=h+j],a[k]=(a[j]-T)%mo,a[j]=(a[j]+T)%mo;
}
void intt(int *a){
REP(i,1,N>>1)swap(a[i],a[N-i]);ntt(a);
ll n=qpow(N,mo-2);REP(i,0,N)a[i]=n*a[i]%mo;
}
void inv(int *a){
static int b[K],c[K],n;n=N;
REP(i,1,N+N)b[i]=c[i]=0;
b[0]=qpow(a[0],mo-2);
for(N=2;N<=n;){
REP(i,0,N)c[i]=a[i];N<<=1;
ntt(c);ntt(b);
REP(i,0,N)b[i]=(2-1ll*b[i]*c[i])%mo*b[i]%mo;
intt(b);REP(i,N>>1,N)b[i]=0;
}N>>=1;REP(i,0,N)a[i]=b[i];
}
void mod(int *a,int na){
static int c[K],d[K],nc,nb;
nb=t;nc=na-nb+1;
if(na<nb)return;
REP(i,0,nc)c[i]=a[na-1-i],d[i]=D[i];
adjust(N,nc+nc-1);REP(i,nc,N)d[i]=c[i]=0;
ntt(c);ntt(d);REP(i,0,N)c[i]=1ll*c[i]*d[i]%mo;
intt(c);
adjust(N,na);REP(i,nc,N)c[i]=0;
REP(i,0,nb)d[i]=G[i];REP(i,nb,N)d[i]=0;
ntt(c);ntt(d);REP(i,0,N)c[i]=1ll*c[i]*d[i]%mo;
intt(c);
REP(i,0,na)a[i]=(a[i]-c[na-1-i])%mo;
}
//倍增用递归版的会更快
int qmod(ll m,int *a,int *r){
if(m<t){r[m]=1;return m+1;}
int l=qmod(m/2,a,r);adjust(N,l<<=1);
ntt(r);REP(i,0,N)r[i]=1ll*r[i]*r[i]%mo;intt(r);
if(m&1){RED(i,N,0)r[i+1]=r[i];r[0]=0;}else --l;
mod(r,l);return min(l,t-1);
}
int c(int n,int m){
int r=1;REP(i,1,m+1)r=1ll*r*qpow(i,mo-2)%mo*(n+1-i)%mo;return r;
}
int main(){
scanf("%lld %d",&n,&k);
if(n<k){printf("0");return 0;}
int C=c(n,k);
if(n<k*(k-1)/2){printf("%d",C);return 0;}
prep();
G[0]=G[2]=1;G[1]=mo-2;t=3;
REP(i,1,k){
RED(j,t,0)G[i+j]=(G[i+j]-G[j])%mo;t+=i;
}N=1;adjust(N,t+t);
REP(i,0,N)F[i]=G[i],D[i]=G[i];inv(F);
n-=k*(k-1)/2;m=n-t+1;
if(n<t+t){
printf("%d",(1ll*C+mo-F[n])%mo);
return 0;
}
//没有对其操作是因为特征多项式要反过来,再翻一次就恢复原样
inv(D);//先预先反过来求个逆,不然倍增一次次求太慢
static int r[K];
REP(i,0,t+t)r[i]=0;
qmod(m,G,r);
int ans=0;
REP(i,0,t)ans=(ans+1ll*r[i]*F[t-1+i])%mo;
printf("%d",(1ll*C+mo-ans)%mo);
}