「解题报告」P5824 十二重计数法

「解题报告」P5824 十二重计数法

orz \(\mathsf{E}\color{red}{\mathsf{ntropyIncreaser}}\) .

  • \(\text{I}\):球之间互不相同,盒子之间互不相同。
    每个球 \(m\) 种放法 . 答案是 \(m^n\) .

  • \(\text{II}\):球之间互不相同,盒子之间互不相同,每个盒子至多装一个球。
    考虑选出会有球的盒子,方案数为 \(\binom{m}{n}\),然后再分配球 . 答案为 \(\binom{m}{n}n! = m^{\underline{n}}\) .
    哦原来你是排列数啊 .

  • \(\text{III}\):球之间互不相同,盒子之间互不相同,每个盒子至少装一个球。
    \(\text{VI}\) 的区别是盒子有顺序,于是乘上顺序就行了 . \(\begin{Bmatrix}n\\m\end{Bmatrix}m!\) .
    好像说容斥能出来斯特林数通项公式 .

  • \(\text{IV}\):球之间互不相同,盒子全部相同。
    感觉像是斯特林数定义,但是允许有空集所以枚举集合数量 . \(\sum_{i = 0}^{m}\begin{Bmatrix}n\\i\end{Bmatrix}\) .

  • \(\text{V}\):球之间互不相同,盒子全部相同,每个盒子至多装一个球。
    什么绝世好题系列 .
    考虑到最终只会有 \(n\) 个盒子有球且不计顺序,如果有方案则只有一种 . \([n \le m]\) .

  • \(\text{VI}\):球之间互不相同,盒子全部相同,每个盒子至少装一个球。
    不允许有空集就是斯特林数了,答案是 \(\begin{Bmatrix}n\\m\end{Bmatrix}\) .

  • \(\text{VII}\):球全部相同,盒子之间互不相同。
    考虑插板法,\(\binom{n + m - 1}{m - 1}\) .

  • \(\text{VIII}\):球全部相同,盒子之间互不相同,每个盒子至多装一个球。
    选出 \(n\) 个盒子有球但是不计顺序,过典组合数 \(\binom{m}{n}\) .

  • \(\text{IX}\):球全部相同,盒子之间互不相同,每个盒子至少装一个球。
    球相同就先把每个盒子需要的一个球放进来,变成 \(\text{VII}\),答案是 \(\binom{n - 1}{m - 1}\) .

  • \(\text{X}\):球全部相同,盒子全部相同。
    相当于一个背包,每种价值都存在 .
    于是直接套用付公主的背包做法即可 .

  • \(\text{XI}\):球全部相同,盒子全部相同,每个盒子至多装一个球。
    \(\text{V}\) 一样 . \([n \le m]\) .

  • \(\text{XII}\):球全部相同,盒子全部相同,每个盒子至少装一个球。
    先把必须用的球放进来,就变成了 \(\text{X}\) .

Code:

const int N = 2e5 + 10, P = 998244353;
namespace POLY {
	const int N=6e5+10,P=998244353,g=3,invg=332748118;int rev[N],omega[2][N];
	std::mt19937 rnd (std::chrono::system_clock::now ().time_since_epoch ().count ());
	template<typename T1,typename T2>inline T1 add(T1 a,T2 b){return(a+=b)>=POLY::P?a-POLY::P:a;}template<typename T1,typename T2>inline void addi(T1&a,T2 b){(a+=b)>=POLY::P?a-=POLY::P:a;return;}template<typename T1,typename...Args>inline T1 add(T1 a,Args...b){return add(a,add(b...));}template<typename T1,typename...Args>inline void addi(T1&a,Args...b){addi(a,add(b...));return;}
	template<typename T1,typename T2>inline T1 sub(T1 a,T2 b){return(a-=b)<0?a+POLY::P:a;}template<typename T1,typename T2>inline void subi(T1&a,T2 b){(a-=b)<0?a+=POLY::P:a;return;}template<typename T1,typename...Args>inline T1 sub(T1 a,Args...b){return sub(a,add(b...));}template<typename T1,typename...Args>inline void subi(T1&a,Args...b){subi(a,add(b...));return;}
	template<typename T1,typename T2>inline T1 mul(T1 a,T2 b){return(1ll*a*b)%POLY::P;}template<typename T1,typename T2>inline void muli(T1&a,T2 b){a=mul(a,b);return;}template<typename T1,typename...Args>T1 inline mul(T1 a,Args...b){return mul(a,mul(b...));}template<typename T1,typename...Args>inline void muli(T1&a,Args...b){muli(a,mul(b...));return;}
	template<typename T1,typename T2>inline T1 FastPow(T1 a,T2 b){T1 ans=1;while(b){if(b&1)muli(ans,a);muli(a,a),b>>=1;}return ans;}template<typename T>inline T inv(T a){return FastPow(a,POLY::P-2);}
	inline int PreWork(const int &n){int lim=1,l=0;while(lim<=n)lim<<=1,++l;_for(i,0,lim)rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));omega[0][0]=omega[1][0]=1;omega[0][1]=FastPow(g,(POLY::P-1)/lim);omega[1][1]=FastPow(invg,(POLY::P-1)/lim);_for(i,2,lim)omega[0][i]=mul(omega[0][i-1],omega[0][1]),omega[1][i]=mul(omega[1][i-1],omega[1][1]);return lim;}
	namespace Cipolla{int _i_;class Complex{public:int real,imag;Complex()=default;Complex(int _real,int _imag):real(_real),imag(_imag){}inline void operator*=(Complex b){int tmp1=add(mul(real,b.real),mul(imag,b.imag,_i_));int tmp2=add(mul(real,b.imag),mul(imag,b.real));real=tmp1,imag=tmp2;return;}};inline int FastPow(Complex a,int b){Complex ans(1,0);while(b){if(b&1)ans*=a;a*=a,b>>=1;}return ans.real;}inline int Cipolla(int n){if (!n)return 0;if (POLY::FastPow(n,(POLY::P-1)>>1)==POLY::P-1)return -1;int a;while(a){a=rnd()%POLY::P,_i_=sub(mul(a,a),n);if(POLY::FastPow(_i_,(POLY::P-1)>>1)==POLY::P-1)break;}return FastPow(Complex(a,1),(POLY::P+1)>>1);}};
	template<typename T = int> class Poly {
	private:std::vector<T>A;
	public:
		Poly()=default;Poly(int len){A.resize(len);return;}Poly(std::vector<T> _A):A(_A){}Poly(typename std::vector<T>::iterator bg,typename std::vector<T>::iterator ed){A.assign(bg,ed);return;}Poly(typename std::vector<T>::iterator bg,int len){A.assign(bg,bg+len);return;}
		inline T& operator[](const int& x){return A[x];}inline T operator[](const int& x)const{return A[x];}
		inline int deg()const{return A.size()-1;}inline int len()const{return A.size();}inline Poly resize(int len){A.resize(len);return(*this);}
		inline typename std::vector<T>::iterator begin(){return A.begin();}inline typename std::vector<T>::iterator end(){return A.end();}inline T* data(){return A.data();}
		inline void assign(typename std::vector<T>::iterator bg,typename std::vector<T>::iterator ed){A.assign(bg,ed);return;}inline void assign(typename std::vector<T>::iterator bg,int len){A.assign(bg,bg+len);return;}
		inline void reverse(){std::reverse(A.begin(),A.end());}inline void reverse(int l,int r){std::reverse(A.begin()+l,A.end()+r+1);}
		inline Poly slice(int n){return n<=0?Poly(0):(n<len()?Poly(begin(),begin()+n+1):Poly(*this).resize(n+1));}inline void clear(){std::vector<T>().swap(A);return;}
		inline void NTT(int lim,bool type){resize(lim);_for(i,0,lim-1)if(i<rev[i])std::swap(A[i],A[rev[i]]);for(int mid=1,t=lim>>1;mid<lim;mid<<=1,t>>=1){for(int R=mid<<1,j=0;j<lim;j+=R){_for(k,0,mid-1){T x=A[j+k],y=mul(omega[type][t*k],A[j+mid+k]);A[j+k]=add(x,y),A[j+mid+k]=sub(x,y);}}}if(type==1){T inv_lim=FastPow(lim,POLY::P-2);_for(i,0,lim-1)A[i]=mul(A[i],inv_lim);}return;}
		friend inline Poly operator+(Poly F,Poly G){F.resize(std::max(F.len(),G.len()));_for(i,0,G.deg())addi(F[i],G[i]);return F;}inline Poly&operator+=(Poly G){resize(std::max(len(),G.len()));_for(i,0,G.deg())addi(A[i],G[i]);return(*this);}
		friend inline Poly operator+(Poly F,T x){addi(F[0],x);return F;}friend inline Poly operator+(T x,Poly F){addi(F[0],x);return F;}inline Poly&operator+=(T x){addi(A[0],x);return(*this);}
		friend inline Poly operator-(Poly F,Poly G){F.resize(std::max(F.len(),G.len()));_for(i,0,G.deg())subi(F[i],G[i]);return F;}inline Poly&operator-=(Poly G){resize(std::max(len(),G.len()));_for(i,0,G.deg())subi(A[i],G[i]);return(*this);}
		friend inline Poly operator-(Poly F,T x){subi(F[0],x);return F;}friend inline Poly operator-(T x,Poly F){subi(F[0],x);return F;}inline Poly&operator-=(T x){subi(A[0],x);return(*this);}
		friend inline Poly operator*(Poly F,Poly G){int lim=PreWork(F.deg()+G.deg());F.NTT(lim,0),G.NTT(lim,0);_for(i,0,lim-1)muli(F[i],G[i]);F.NTT(lim,1);return F;}inline Poly&operator*=(Poly G){int lim=PreWork(deg()+G.deg());NTT(lim,0),G.NTT(lim,0);_for(i,0,lim-1)muli(A[i],G[i]);NTT(lim,1);return(*this);}
		friend inline Poly operator*(Poly F,T x){_for(i,0,F.deg())muli(F[i],x);return F;}friend inline Poly operator*(T x,Poly F){_for(i,0,F.deg())muli(F[i],x);return F;}inline Poly&operator*=(T x){_for(i,0,deg())muli(A[i],x);return(*this);}
		friend inline Poly operator/(Poly F,T x){x=POLY::inv(x);return F*x;}friend inline Poly operator/(T x,Poly F){x=POLY::inv(x);return F*x;}inline Poly&operator/=(T x){x=POLY::inv(x);(*this)*=x;return(*this);}
		friend inline Poly operator<<(Poly F,int x){F.resize(F.len()+x),memmove(F.data()+x,F.data(),4*(F.len()-x)),memset(F.data(),0,4*x);return F;}inline Poly&operator<<=(int x){resize(len()+x),memmove(data()+x,data(),4*(len()-x)),memset(data(),0,4*x);return(*this);}
		friend inline Poly operator>>(Poly F,int x){if(x>=F.len())F.clear();else memmove(F.data(),F.data()+x,4*(F.len()-x)),F.resize(F.len()-x);return F;}inline Poly& operator>>=(int x){return x>=len()?(clear(),*this):(memmove(data(),data()+x,4*(len()-x)),resize(len()-x),*this);}
		inline Poly inv(){Poly G(1);if(A.empty())return G;G[0]=POLY::inv(A[0]);Poly t[2];for(int l=2;l<(len()<<1);l<<=1){t[0].assign(A.begin(),std::min(l,len()));t[1]=G,t[1].resize(std::min(l,len()));int lim=PreWork(t[0].deg()+t[1].deg()+1);t[0].NTT(lim,0),t[1].NTT(lim,0),G.resize(lim);_for(i,0,lim-1)G[i]=mul(sub(2,mul(t[0][i],t[1][i])),t[1][i]);G.NTT(lim,1),G.resize(l);}G.resize(len());return G;}
		inline Poly sqrt(){Poly G(1);G[0]=Cipolla::Cipolla(A[0]),G[0]=std::min(G[0],POLY::P-G[0]);T inv2=POLY::inv(2);Poly t[2];for(int l=2;l<(len()<<1);l<<=1){t[1].assign(A.begin(),std::min(l,len()));G.resize(l),t[0]=G.inv()*t[1];_for(i,0,l-1)G[i]=mul(t[0][i]+G[i],inv2);}G.resize(len());return G;}
		inline Poly differential(){Poly G(len()-1);_for(i,0,deg()-1)G[i]=mul(A[i+1],i+1);return G;}inline void iDifferential(){_for(i,0,deg()-1)A[i]=mul(A[i+1],i+1);A.resize(len()-1);return;}
		inline Poly integral(){Poly G(len());for_(i,deg(),1)G[i]=mul(A[i-1],POLY::inv(i));return G;}inline void iIntegral(){A.resize(len());for_(i,deg(),1)A[i]=mul(A[i-1],POLY::inv(i));A[0]=0;return;}
		inline Poly ln(){Poly G=(differential()*inv()).integral();G.resize(len());return G;}
		inline Poly exp(){Poly G(1),H;G[0]=1;T inv2=POLY::inv(2);for(int l=2;l<(len()<<1);l<<=1)G.resize(l),H.assign(A.begin(),std::min(l,len())),H-=G.ln(),++H[0],G*=H;G.resize(len());return G;}
		inline Poly power(int k){if(A[0]!=0)return((((*this)*FastPow(A[0],P-2)).ln())*k).exp()*FastPow(A[0],k);else _for(i,0,deg())if(A[i]!=0)return((*this)>>i).Power(k)<<(i*k);return Poly(len());}
		inline Poly power(pii k){if(A[0]!=0)return((((*this)*FastPow(A[0],P-2)).ln())*k.second).exp()*FastPow(A[0],k.first);else _for(i,0,deg())if(A[i]!=0)return(1ll*i*k.first)>len()?Poly(len()):((*this)>>i).Power(k)<<(i*k.first);return Poly(len());};
	};
} using poly = POLY::Poly<int>;
namespace MATH {
	int fpow (int a, int b, int ans = 1) {
		for (b += (b < 0) * (P - 1); b; a = 1ll * a * a % P, b >>= 1)
			if (b & 1) ans = 1ll * ans * a % P;
		return ans;
	} // This is fast pow. You can change the initial value.
	namespace binom {
		std::vector <std::uint32_t> __fac ({ 1, 1 }), __inv ({ 0, 1 }), __invf ({ 1, 1 });
		inline void __prep (int x) {
			static int i = 2;
			if (i < x) {
				for (__fac.resize (x), __inv.resize (x), __invf.resize (x); i < x; ++i) {
					__fac[i] = 1ull * __fac[i - 1] * i % P;
					__inv[i] = 1ull * (P - P / i) * __inv[P % i] % P;
					__invf[i] = 1ull * __invf[i - 1] * __inv[i] % P;
				}
			}
			return;
		} inline int gfac (int x) {
			return (x < 0) ? 0 : (__prep (x + 1), __fac[x]);
		} inline int ginv (int x) {
			return (x < 0) ? 0 : (__prep (x + 1), __inv[x]);
		} inline int ginvf (int x) {
			return (x < 0) ? 0 : (__prep (x + 1), __invf[x]);
		} inline int C (int n, int m) {
			return (n < m) ? 0 : 1ll * gfac (n) * ginvf (n - m) % P * ginvf (m) % P;
		}
	} // namespace binom
	using binom::gfac, binom::ginv, binom::ginvf, binom::C;
} // namespace MATH
using namespace MATH;
namespace SOLVE {
	int n, m, a[N], ans;
	poly S;
	inline int rnt () {
		int x = 0, w = 1; char c = getchar ();
		while (!isdigit (c)) { if (c == '-') w = -1; c = getchar (); }
		while (isdigit (c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar ();
		return x * w;
	}
	inline void In () {
		n = rnt (), m = rnt ();
		poly F (n + 1), G (n + 1);
		_for (i, 0, n) {
			F[i] = 1ll * fpow (i, n) * ginvf (i) % P;
			G[i] = (i & 1) ? P - ginvf (i) : ginvf (i);
		}
		S = F * G;
		return;
	}
	inline int SolveI () {
		return fpow (m, n);
	}
	inline int SolveII () {
		return 1ll * gfac (m) * ginvf (m - n) % P;
	}
	inline int SolveIII () {
		return m > n ? 0 : 1ll * S[m] * gfac (m) % P;
	}
	inline int SolveIV () {
		ll ans = 0;
		_for (i, 0, std::min (n, m)) ans += S[i];
		return ans % P;
	}
	inline int SolveV () {
		return (n <= m);
	}
	inline int SolveVI () {
		return m > n ? 0 : S[m];
	}
	inline int SolveVII () {
		return C (n + m - 1, m - 1);
	}
	inline int SolveVIII () {
		return C (m, n);
	}
	inline int SolveIX () {
		return C (n - 1, m - 1);
	}
	inline int SolveX () {
		poly F (n + 1);
		_for (i, 1, m) _for (j, 1, n / i)
			F[i * j] = (F[i * j] + ginv (j)) % P;
		F = F.exp ();
		return F[n];
	}
	inline int SolveXI () {
		return (n <= m);
	}
	inline int SolveXII () {
		poly F (n + 1);
		_for (i, 1, m) _for (j, 1, n / i)
			F[i * j] = (F[i * j] + ginv (j)) % P;
		F = F.exp ();
		return n < m ? 0 : F[n - m];
	}
	inline void Out () {
		printf ("%d\n", SolveI ());
		printf ("%d\n", SolveII ());
		printf ("%d\n", SolveIII ());
		printf ("%d\n", SolveIV ());
		printf ("%d\n", SolveV ());
		printf ("%d\n", SolveVI ());
		printf ("%d\n", SolveVII ());
		printf ("%d\n", SolveVIII ());
		printf ("%d\n", SolveIX ());
		printf ("%d\n", SolveX ());
		printf ("%d\n", SolveXI ());
		printf ("%d\n", SolveXII ());
		return;
	}
}
posted @ 2023-10-16 07:20  K8He  阅读(82)  评论(0编辑  收藏  举报