【模拟赛12.28】T1

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 n109,k200


什么凸多边形。。。搞得很难的样子,就是求选取方案种数使得最小的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(ni+1)fi,k1(最大的数>=除最大数的和=i)
f i , j f_{i,j} fi,j表示选j个拼i的方案数
假设选出来的 a 1 &lt; a 2 &lt; ⋯ &lt; a k a_1&lt;a_2&lt;\cdots&lt;a_k a1<a2<<ak
其差分 d 1 , d 2 , ⋯ &ThinSpace; , d k &gt; 0 d_1,d_2,\cdots,d_k&gt;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 (k1)d1+(k2)d2++dk1=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,k1=[xi]i=1k11xixi
因为 i d ( i ) = i + 1 id(i)=i+1 id(i)=i+1的OGF是 1 ( 1 − x ) 2 \frac 1{(1-x)^2} (1x)21
∑ i = 1 n ( n − i + 1 ) f i , k − 1 \sum_{i=1}^n (n-i+1)f_{i,k-1} i=1n(ni+1)fi,k1是个卷积
( 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][(1x)21i=1k11xixi]=[xn21k(k1)][(1x)2i=1k11xi1]
m = n − 1 2 k ( k − 1 ) m=n-\frac12k(k-1) m=n21k(k1)

我们发现下面的 ( 1 − x ) 2 ∏ i = 1 k − 1 1 − x i (1-x)^2\prod_{i=1}^{k-1}1-x^i (1x)2i=1k11xi可以表示成 1 − G ( x ) 1-G(x) 1G(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)=1G(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=1nfnigi,这可以看做一个递推
设关于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=f1f2ft
设其转移矩阵为 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 &amp; g_2 &amp; \cdots &amp; g_{t-1} &amp; g_t\\ 1 &amp; 0 &amp; \cdots &amp; 0 &amp; 0 \\ 0 &amp; 1 &amp; \cdots &amp; 0 &amp; 0\\ \vdots &amp; \vdots &amp; \ddots &amp; \vdots &amp; \vdots\\ 0 &amp; 0 &amp; \cdots &amp; 1 &amp; 0\\ \end{bmatrix} T=g1100g2010gt1001gt000
那么要求的 f m f_m fm可以通过求 A T m − t AT^{m-t} ATmt

假设我们要求 T m T^m Tm
但是t很大,m也很大
有一个叫做凯莱·哈密顿定理的东西
T的特征多项式 r ( λ ) = det ⁡ ( λ I − T ) r(\lambda)=\det(\lambda I-T) r(λ)=det(λIT)
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)=xti=1tgixtii

r ( x ) r(x) r(x)只有t项!
如果求出 x m m o d &ThinSpace;&ThinSpace; r ( x ) x^m\mod r(x) xmmodr(x)再把T带进去就可以把指数大大缩小
这个可以倍增+多项式取模求

假设已经求出了 h ( x ) = x m m o d &ThinSpace;&ThinSpace; 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 &ThinSpace;&ThinSpace; 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 ) ∣ &lt; ∣ B ( x ) ∣ |D(x)|&lt;|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)×xnmC(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),xnmC(x)都相当于将他们反过来
只有 D ( x ) D(x) D(x)的前n-m项系数都是0,
两边同时 m o d &ThinSpace;&ThinSpace; x n − m \mod x^{n-m} modxnm
消去 D ′ ( x ) D&#x27;(x) D(x)(这里用“ ′ &#x27; ”表示将其反过来的多项式)变为 A ′ ( x ) = B ′ ( x ) C ′ ( x ) ( m o d &ThinSpace;&ThinSpace; x n − m ) A&#x27;(x)=B&#x27;(x)C&#x27;(x)(\mod x^{n-m}) A(x)=B(x)C(x)(modxnm)
C ′ ( x ) = A ′ ( x ) B ′ ( x ) m o d &ThinSpace;&ThinSpace; x n − m C&#x27;(x)=\frac{A&#x27;(x)}{B&#x27;(x)}\mod x^{n-m} C(x)=B(x)A(x)modxnm用一个多项式求逆
然后再乘回去求出 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);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值