2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)- 分组(矩阵快速幂套NTT优化dp)
Posted Frozen_Guardian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)- 分组(矩阵快速幂套NTT优化dp)相关的知识,希望对你有一定的参考价值。
题目链接:点击查看
题目大意:给出 n n n 个连续的小球,每次可以选择单独的一个或者相邻的两个小球分成一组,允许有剩余的小球,问恰好分成 k ∈ 1 , 2 , 3 , ⋯ , m k\\in\\1,2,3,\\cdots,m\\ k∈1,2,3,⋯,m 组的方案数分别是多少。
题目分析:设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 为前
i
i
i 个小球分成
j
j
j 组的方案数,不难推出:
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
]
+
d
p
[
i
−
1
]
[
j
−
1
]
+
d
p
[
i
−
2
]
[
j
−
1
]
dp[i][j]=dp[i-1][j]+dp[i-1][j-1]+dp[i-2][j-1]
dp[i][j]=dp[i−1][j]+dp[i−1][j−1]+dp[i−2][j−1]
由于不会特征方程求解通项公式,只会用矩阵快速幂套多项式优化上述过程,时间复杂度 O ( m log n log m ) O(m\\log n\\log m) O(mlognlogm),比赛时无论如何卡常都 T L E TLE TLE,但是补题的时候交了一发很神奇的卡常卡过去了,离谱。
然后这个模板在矩阵自乘的时候做了一些小优化,将原本 8 8 8 次的 D F T DFT DFT 下降成了 4 4 4 次,可以说是优化了很多了。
具体推导可以参考:2021HDU多校8 - 7057 Buying Snacks
一份常数更小的代码:
#include<bits/stdc++.h>
using namespace std;
#define SZ(x) ((int)(x).size())
#define rep(i,a) for(int i=0;i<(a);++i)
#define repi(i,a) for(int i=1;i<=(a);++i)
template<typename T>
inline void write(T x)
if(x<0)x=~(x-1);putchar('-');
if(x>9)write(x/10);
putchar(x%10+'0');
typedef long long ll;
const int Inf=0x3f3f3f3f;
const int jt=998244353,rg=3,mlg=20;
void inline add(int &a,int b)
a+=b-jt;
a+=(a>>31)&jt;
void inline sub(int &a,int b)
a-=b;
a+=(a>>31)&jt;
void inline mul(int &a,int b)
a=(ll)a*b%jt;
int inline Add(int a,int b)
return a+b>=jt?a+b-jt:a+b;
int inline Sub(int a,int b)
return a-b<0?a-b+jt:a-b;
int inline Mul(int a,int b)
return (ll)a*b%jt;
typedef vector<int>Poly;
int inline ksmii(int a,int b)
int res=1;
while(b)
if(b&1)
mul(res,a);
mul(a,a);
b>>=1;
return res;
namespace Fourier
int ho[mlg+1][1<<mlg],omg[mlg+1][1<<mlg],in[mlg+1];
void init()
rep(lg,mlg+1)
int N=1<<lg;
if(lg)
rep(i,N)
ho[lg][i]=(ho[lg][i>>1]>>1)|((i&1)<<(lg-1));
int omega=ksmii(rg,(jt-1)>>(lg+1)),ome=1;
rep(i,N) omg[lg][i]=ome,mul(ome,omega);
in[lg]=ksmii(N,jt-2);
void inline fft(int a[],int lg,int inv)
int N=1<<lg;
rep(i,N)
if(ho[lg][i]<i)
swap(a[i],a[ho[lg][i]]);
rep(l,lg)
int i=1<<l;
for(int j=0;j<N;j+=i<<1)
int *x=a+j,*y=x+i,*o=omg[l],tmp;
rep(k,i)
tmp=Mul(*y,*o);
*y=Sub(*x,tmp);
add(*x,tmp);
++x,++y,++o;
if(!~inv)
reverse(a+1,a+N);
rep(i,N)
mul(a[i],in[lg]);
int N,M;
int tmp[2][2][1<<mlg],tmq[2][2][1<<mlg],tmr[2][2][1<<mlg];
struct Matrix
Poly a[2][2];
inline Poly *operator[](int x)
return a[x];
inline const Poly *operator[](int x) const
return a[x];
inline Matrix operator*(const Matrix &b) const
int ts1=0,ts2=0;
rep(i,2) rep(j,2) ts1=max(ts1,SZ(a[i][j]));
rep(i,2) rep(j,2) ts2=max(ts2,SZ(b[i][j]));
int ts=ts1+ts2,lg=0;
while((1<<lg)<ts) ++lg;
int N=1<<lg;
rep(i,2) rep(j,2)
rep(k,N) tmp[i][j][k]=k<SZ(a[i][j])?a[i][j][k]:0;
Fourier::fft(tmp[i][j],lg,1);
rep(i,2) rep(j,2)
rep(k,N) tmq[i][j][k]=k<SZ(b[i][j])?b[i][j][k]:0;
Fourier::fft(tmq[i][j],lg,1);
rep(i,2) rep(j,2) rep(k,N) tmr[i][j][k]=0;
rep(p,N) rep(i,2) rep(j,2) rep(k,2) add(tmr[i][k][p],Mul(tmp[i][j][p],tmq[j][k][p]));
rep(i,2) rep(j,2) Fourier::fft(tmr[i][j],lg,-1);
Matrix res;
if(ts>M+5) ts=M+5;
rep(i,2) rep(j,2)
res[i][j].resize(ts);
rep(k,ts) res[i][j][k]=tmr[i][j][k];
return res;
;
void MUL(Matrix &a)
int ts=0;
rep(i,2) rep(j,2) ts=max(ts,SZ(a[i][j]));
int lg=0;
ts*=2;
while((1<<lg)<ts) ++lg;
int N=1<<lg;
rep(i,2) rep(j,2)
rep(k,N) tmp[i][j][k]=k<SZ(a[i][j])?a[i][j][k]:0;
Fourier::fft(tmp[i][j],lg,1);
rep(i,2) rep(j,2) rep(k,N) tmr[i][j][k]=0;
rep(p,N) rep(i,2) rep(j,2) rep(k,2) add(tmr[i][k][p],Mul(tmp[i][j][p],tmp[j][k][p]));
rep(i,2) rep(j,2) Fourier::fft(tmr[i][j],lg,-1);
if(ts>M+5) ts=M+5;
rep(i,2) rep(j,2)
a[i][j].resize(ts);
rep(k,ts) a[i][j][k]=tmr[i][j][k];
inline Matrix ksmii(Matrix a,int b)
Matrix res;
rep(i,2) rep(j,2) res[i][j]=i==j?Poly1:Poly;
while(b)
if(b&以上是关于2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)- 分组(矩阵快速幂套NTT优化dp)的主要内容,如果未能解决你的问题,请参考以下文章
2021-2022年度第三届全国大学生算法设计与编程挑战赛(冬季赛)-正式赛 部分题解
2021-2022年度第三届全国大学生算法设计与编程挑战赛(冬季赛正式赛) 部分题题解
2021-2022年度第三届全国大学生算法设计与编程挑战赛(冬季赛正式赛) 部分题题解
2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)- 占座位(最小割)