HAOI2018染色——容斥

本文介绍了一种利用NTT(Number Theoretic Transform)优化组合计数问题的方法,特别是针对颜色方案计数的问题。通过分治FFT和二项式反演技术,实现了高效的计算方案。代码示例展示了具体的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意

loj

思路

f i f_i fi表示至少出现了i种颜色的方案数

f i = ( m i ) × ( s × i ) ! ( s ! ) i × ( n s × i ) × ( m − i ) n − s × i f i = ( m i ) × n ! ( s ! ) i × ( n − s × i ) ! × ( m − i ) n − s × i \begin{aligned} f_i&={m \choose i}\times \frac{(s\times i)!}{(s!)^{i}}\times {n\choose s\times i}\times (m-i)^{n-s\times i}\\ f_i&={m \choose i}\times \frac{n!}{(s!)^{i}\times (n-s\times i)!}\times (m-i)^{n-s\times i}\\ \end{aligned} fifi=(im)×(s!)i(s×i)!×(s×in)×(mi)ns×i=(im)×(s!)i×(ns×i)!n!×(mi)ns×i

g i g_i gi表示恰好出现了i种颜色的方案数,不难得到 g i g_i gi的容斥式子。

g i = f i − ∑ j = i + 1 m g j × ( j i ) g i = f i − ∑ j = i + 1 m × g j × j ! ( j − i ) ! i ! \begin{aligned} g_i=&f_i-\sum_{j=i+1}^{m}g_{j}\times {j\choose i}\\ g_i=&f_i-\frac{\sum_{j=i+1}^{m}\times \frac{g_j\times j!}{(j-i)!}}{i!} \end{aligned} gi=gi=fij=i+1mgj×(ij)fii!j=i+1m×(ji)!gj×j!

上面是一个经典的分治FFT形式的式子,使用分治FFT可以做到 n log ⁡ 2 n n\log^2n nlog2n

其实可以更加优化,上面的式子同样也是一个经典的二项式反演。

f i = ∑ j = i m ( j i ) × g j g i = ∑ j = i m ( − 1 ) j − i × ( j i ) × f j \begin{aligned} f_i&=\sum_{j=i}^{m}{j\choose i}\times g_{j}\\ g_i&=\sum_{j=i}^{m}(-1)^{j-i}\times {j\choose i}\times f_{j} \end{aligned} figi=j=im(ij)×gj=j=im(1)ji×(ij)×fj

直接用NTT一遍求出g的值即可。

/*=======================================
 * Author : ylsoi
 * Time : 2019.3.22
 * Problem : loj2527_ntt
 * E-mail : ylsoi@foxmail.com
 * ====================================*/
#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<" "
#define fi first
#define se second
#define mk make_pair
#define pb push_back
typedef long long ll;

using namespace std;

void File(){
	freopen("loj2527_ntt.in","r",stdin);
	freopen("loj2527_ntt.out","w",stdout);
}

template<typename T>void read(T &_){
	_=0; T f=1; char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
	_*=f;
}

string proc(){
	ifstream f("/proc/self/status");
	return string(istreambuf_iterator<char>(f),istreambuf_iterator<char>());
}

const int maxn=1e7+10;
const int maxm=1e5+10;
const int mod=1004535809;
int n,m,S,w[maxm],ans;
int fac[maxn],ifac[maxn];

int qpow(int x,int y=mod-2){
	int ret=1; x%=mod;
	while(y){
		if(y&1)ret=1ll*ret*x%mod;
		x=1ll*x*x%mod;
		y>>=1;
	}
	return ret;
}

void inc(int &x,int y){
	x+=y;
	if(x>=mod)x-=mod;
	else if(x<0)x+=mod;
}

int C(int x,int y){
	if(x<0 || y<0 || x<y)return 0;
	return 1ll*fac[x]*ifac[y]%mod*ifac[x-y]%mod;
}

namespace Poly{
	int om[maxm<<2],dn[maxm<<2],lim,cnt;
	void dft(int *A,int ty){
		if(ty==-1)reverse(A+1,A+lim);
		REP(i,0,lim-1)if(i<dn[i])swap(A[i],A[dn[i]]);
		for(int len=1;len<lim;len<<=1){
			int w=om[len<<1];
			for(int L=0;L<lim;L+=len<<1){
				int wk=1;
				REP(i,L,L+len-1){
					int u=A[i],v=1ll*A[i+len]*wk%mod;
					A[i]=(u+v)%mod;
					A[i+len]=(u-v)%mod;
					wk=1ll*wk*w%mod;
				}
			}
		}
		if(ty==-1){
			int inv=qpow(lim);
			REP(i,0,lim-1)A[i]=(1ll*A[i]*inv%mod+mod)%mod;
		}
	}
}

void init(){
	read(n),read(m),read(S);
	REP(i,0,m)read(w[i]);
	fac[0]=1;
	int lim=max(n,m);
	REP(i,1,lim)fac[i]=1ll*fac[i-1]*i%mod;
	ifac[lim]=qpow(fac[lim]);
	DREP(i,lim-1,0)ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
}

int f[maxm<<2],g[maxm<<2];

using namespace Poly;

int main(){
//	File();
	init();
	REP(i,0,m)if(S*i<=n)f[i]=1ll*C(m,i)*fac[S*i]%mod*
		qpow(ifac[S],i)%mod*C(n,S*i)%mod*qpow(m-i,n-S*i)%mod*fac[i]%mod;
	REP(i,0,m)g[i]=1ll*(i&1 ? -1 : 1)*ifac[i]%mod;
	reverse(g,g+m+1);

	lim=1,cnt=0;
	while(lim<=m+m)lim<<=1,++cnt;
	if(!cnt)cnt=1;
	om[lim]=qpow(3,(mod-1)/lim);
	for(int i=lim>>1;i;i>>=1)
		om[i]=1ll*om[i<<1]*om[i<<1]%mod;
	REP(i,0,lim-1)dn[i]=dn[i>>1]>>1|((i&1)<<(cnt-1));

	dft(f,1),dft(g,1);
	REP(i,0,lim-1)g[i]=1ll*g[i]*f[i]%mod;
	dft(g,-1);

	REP(i,0,m)inc(ans,1ll*g[i+m]*w[i]%mod*ifac[i]%mod);
	printf("%d\n",ans);

	return 0;
}
/*=======================================
 * Author : ylsoi
 * Time : 2019.3.21
 * Problem : loj2527
 * E-mail : ylsoi@foxmail.com
 * ====================================*/
#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<" "
#define fi first
#define se second
#define mk make_pair
#define pb push_back
typedef long long ll;

using namespace std;

void File(){
	freopen("loj2527.in","r",stdin);
	freopen("loj2527.out","w",stdout);
}

template<typename T>void read(T &_){
	_=0; T f=1; char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
	_*=f;
}

string proc(){
	ifstream f("/proc/self/status");
	return string(istreambuf_iterator<char>(f),istreambuf_iterator<char>());
}

const int maxn=1e7+10;
const int maxm=1e5+10;
const int mod=1004535809;
int n,m,S,w[maxm],ans;
int fac[maxn],ifac[maxn];

int qpow(int x,int y=mod-2){
	int ret=1; x%=mod;
	while(y){
		if(y&1)ret=1ll*ret*x%mod;
		x=1ll*x*x%mod;
		y>>=1;
	}
	return ret;
}

int C(int x,int y){
	if(x<0 || y<0 || x<y)return 0;
	return 1ll*fac[x]*ifac[y]%mod*ifac[x-y]%mod;
}

void inc(int &x,int y){
	x+=y;
	if(x>=mod)x-=mod;
	else if(x<0)x+=mod;
}

namespace Poly{
	int om[maxm<<2],dn[maxm<<2],lim,cnt;
	void dft(int *A,int ty){
		if(ty==-1)reverse(A+1,A+lim);
		REP(i,0,lim-1)if(i<dn[i])swap(A[i],A[dn[i]]);
		for(int len=1;len<lim;len<<=1){
			int w=om[len<<1];
			for(int L=0;L<lim;L+=len<<1){
				int wk=1;
				REP(i,L,L+len-1){
					int u=A[i],v=1ll*A[i+len]*wk%mod;
					A[i]=(u+v)%mod;
					A[i+len]=(u-v)%mod;
					wk=1ll*wk*w%mod;
				}
			}
		}
		if(ty==-1){
			int inv=qpow(lim);
			REP(i,0,lim-1)A[i]=1ll*A[i]*inv%mod;
		}
	}
	void multi(int *A,int *B,int *C,int la,int lb){
		lim=1,cnt=0;
		while(lim<=la+lb)lim<<=1,++cnt;
		REP(i,0,lim-1){
			dn[i]=dn[i>>1]>>1|((i&1)<<(cnt-1));
			if(i>la)A[i]=0;
			if(i>lb)B[i]=0;
		}
		dft(A,1),dft(B,1);
		REP(i,0,lim-1)C[i]=1ll*A[i]*B[i]%mod;
		dft(C,-1);
	}
}

void math_init(){
	fac[0]=1;
	int lim=max(n,m);
	REP(i,1,lim)fac[i]=1ll*fac[i-1]*i%mod;
	ifac[lim]=qpow(fac[lim],mod-2);
	DREP(i,lim-1,0)ifac[i]=1ll*ifac[i+1]*(i+1)%mod;

	using namespace Poly;
	lim=1;
	while(lim<=m+m)lim<<=1;
	om[lim]=qpow(3,(mod-1)/lim);
	for(int i=lim>>1;i;i>>=1)
		om[i]=1ll*om[i<<1]*om[i<<1]%mod;
}

int f[maxm<<2],g[maxm<<2],ap[maxm<<2],bp[maxm<<2];

void divide(int l,int r){
	if(l==r){
		g[l]=(f[l]-1ll*g[l]*ifac[l]%mod)%mod;
		inc(ans,1ll*g[l]*w[l]%mod);
		return;
	}

	using namespace Poly;
	int mid=(l+r)>>1;

	divide(mid+1,r);

	REP(i,0,r-mid-1)ap[i]=1ll*g[i+mid+1]*fac[i+mid+1]%mod;
	REP(i,0,r-l-1)bp[i]=ifac[i+1];
	reverse(bp,bp+r-l);
	multi(ap,bp,ap,r-mid-1,r-l-1);
	REP(i,l,mid)inc(g[i],ap[i-mid-1+r-l]);

	divide(l,mid);
}

int main(){
	//File();

	read(n),read(m),read(S);
	REP(i,0,m)read(w[i]);

	math_init();

	REP(i,0,m)if(S*i<=n)
		f[i]=1ll*C(m,i)*fac[n]%mod*qpow(ifac[S],i)%mod*ifac[n-S*i]%mod*qpow(m-i,n-S*i)%mod;

	divide(0,m);

	printf("%d\n",ans);

	return 0;
}
概要:本文详细探讨了基于MATLAB/SIMULINK的多载波无线通信系统仿真及性能分析,重点研究了以OFDM为代表的多载波技术。文章首先介绍了OFDM的基本原理和系统组成,随后通过仿真平台分析了不同调制方式的抗干扰性能、信道估计算法对系统性能的影响以及同步技术的实现与分析。文中提供了详细的MATLAB代码实现,涵盖OFDM系统的基本仿真、信道估计算法比较、同步算法实现和不同调制方式的性能比较。此外,还讨论了信道特征、OFDM关键技术、信道估计、同步技术和系统级仿真架构,并提出了未来的改进方向,如深度学习增强、混合波形设计和硬件加速方案。; 适合人群:具备无线通信基础知识,尤其是对OFDM技术有一定了解的研究人员和技术人员;从事无线通信系统设计与开发的工程师;高校通信工程专业的高年级本科生和研究生。; 使用场景及目标:①理解OFDM系统的工作原理及其在多径信道环境下的性能表现;②掌握MATLAB/SIMULINK在无线通信系统仿真中的应用;③评估不同调制方式、信道估计算法和同步算法的优劣;④为实际OFDM系统的设计和优化提供理论依据和技术支持。; 其他说明:本文不仅提供了详细的理论分析,还附带了大量的MATLAB代码示例,便于读者动手实践。建议读者在学习过程中结合代码进行调试和实验,以加深对OFDM技术的理解。此外,文中还涉及了一些最新的研究方向和技术趋势,如AI增强和毫米波通信,为读者提供了更广阔的视野。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值