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[i1][j]+dp[i1][j1]+dp[i2][j1]

由于不会特征方程求解通项公式,只会用矩阵快速幂套多项式优化上述过程,时间复杂度 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?Poly{1}:Poly{};
	while(b2021-2022年度第三届全国大学生算法设计与编程挑战赛(冬季赛)-正式赛 部分题解

2021-2022年度第三届全国大学生算法设计与编程挑战赛(冬季赛正式赛) 部分题题解

2021-2022年度第三届全国大学生算法设计与编程挑战赛(冬季赛正式赛) 部分题题解

2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)- 占座位(最小割)

2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)- 占座位(最小割)

2021-2022年度第三届全国大学生算法设计与编程挑战赛(秋季赛)- 占座位(最小割)