【JZOJ6082】染色问题

Description

有n个格子,现在用m种颜色按顺序染m次,每次可以染一段区间(如果区间内有别的颜色将会被这种颜色覆盖),问最终所有格子都有颜色的情况下,不同的颜色序列有多少种。

Solution

最终序列肯定是一段一段的颜色,其实每次染色相当于从原有的颜色段中插入一段颜色。
f i , j f_{i,j} fi,j表示前 i i i次染色,颜色段长度为 j j j的方案数,容易得到转移就是:
f i , j = f i − 1 , j + ∑ k = 0 j − 1 ( k + 1 ) f i − 1 , k f_{i,j}=f_{i-1,j}+\sum_{k=0}^{j-1}(k+1)f_{i-1,k} fi,j=fi1,j+k=0j1(k+1)fi1,k
f i , j f_{i,j} fi,j看成 f i ( x ) [ x j ] f_i(x)[x^j] fi(x)[xj],转移可以看成 f i ( x ) = f i − 1 ( x ) ( i x + 1 ) f_i(x)=f_{i-1}(x)(ix+1) fi(x)=fi1(x)(ix+1),最后再乘上个组合数,答案可以写成(这里m颜色必须染):
∑ i = 1 m C m − 1 i − 1 ( [ x i ] x ∏ j = 2 n ( j x + 1 ) ) \sum_{i=1}^mC_{m-1}^{i-1}([x^i]x\prod_{j=2}^n(jx+1)) i=1mCm1i1([xi]xj=2n(jx+1))
分治NTT会T,考虑倍增:
f m ( x ) = ∏ i = 1 m ( ( i + 1 ) x + 1 ) f_m(x)=\prod\limits_{i=1}^m((i+1)x+1) fm(x)=i=1m((i+1)x+1), f m ′ ( x ) = ∏ i = m + 1 2 m ( ( i + 1 ) x + 1 ) f_m'(x)=\prod\limits_{i=m+1}^{2m}((i+1)x+1) fm(x)=i=m+12m((i+1)x+1)
那么 f 2 m ( x ) = f m ( x ) f m ′ ( x ) f_{2m}(x)=f_m(x)f_m'(x) f2m(x)=fm(x)fm(x)
考虑求 f m ′ ( x ) f_m'(x) fm(x),改写一下变成 f m ′ ( x ) = ∏ i = 1 m ( ( i + 1 ) x + m x + 1 ) f_m'(x)=\prod\limits_{i=1}^m((i+1)x+mx+1) fm(x)=i=1m((i+1)x+mx+1)
a i = f m ( x ) [ x i ] a_i=f_m(x)[x^i] ai=fm(x)[xi] b i = f m ′ ( x ) [ x i ] b_i=f_m'(x)[x^i] bi=fm(x)[xi],枚举有 f m ( x ) f_m(x) fm(x)有多少个 1 1 1变成了 m m m,可以得到:
b i + j = C m − i j m j a i b_{i+j}=C_{m-i}^jm^ja_i bi+j=Cmijmjai
把组合数拆开,多项式乘法即可。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;++i)
#define fd(i,j,k) for(int i=j;i>=k;--i)
using namespace std;
typedef long long ll;
const int N=1e6+10,M=3e6+10,mo=998244353;
int qpow(int x,int y){
	int s=1;
	for(;y;y>>=1,x=(ll)x*x%mo) if(y&1) s=(ll)s*x%mo;
	return s;
}
int fn;
int jc[N],ny[N];
int rev[M];
int pl(int x,int y){
	return x+y>=mo?x+y-mo:x+y;
}
void NTT(int *a,int sig){
	fo(i,1,fn-1) if(i<rev[i]) swap(a[i],a[rev[i]]);
	for(int m=2;m<=fn;m<<=1){
		int half=m>>1,w0=qpow(3,(mo-1)/m);
		if(sig<0) w0=qpow(w0,mo-2);
		for(int i=0;i<fn;i+=m)
		for(int j=i,w=1;j<i+half;++j,w=(ll)w*w0%mo){
			int u=a[j],v=(ll)a[j+half]*w%mo;
			a[j]=pl(u,v),a[j+half]=pl(u,mo-v);
		}
	}
	if(sig<0){
		int nf=qpow(fn,mo-2);
		fo(i,0,fn-1) a[i]=(ll)a[i]*nf%mo;
	}
}
void mul(int *a,int *b,int ln,int nd){
	int cnt=0;
	for(fn=1;fn<=(ln<<1);fn<<=1) ++cnt;
	fo(i,1,fn-1) rev[i]=rev[i>>1]>>1|(i&1)<<(cnt-1);
	fo(i,ln+1,fn-1) a[i]=b[i]=0;
	NTT(a,1),NTT(b,1);
	fo(i,0,fn-1) a[i]=(ll)a[i]*b[i]%mo;
	NTT(a,-1);
	fo(i,nd+1,fn-1) a[i]=0;
}
int b[M],c[M],d[M];
void solve(int *a,int n){
	if(n==1){
		a[0]=1,a[1]=2;
		return;
	}
	int m=n>>1;
	solve(a,m);
	fo(i,0,m) b[i]=(ll)a[i]*jc[m-i]%mo,c[i]=(ll)qpow(m,i)*ny[i]%mo;
	mul(b,c,m,m);
	fo(i,0,m) b[i]=(ll)b[i]*ny[m-i]%mo;
	mul(a,b,m,m<<1);
	if(n&1){
		c[0]=0;
		fo(i,0,m<<1) c[i+1]=(ll)a[i]*(n+1)%mo;
		fo(i,0,n) a[i]=pl(a[i],c[i]);
	}
}
int C(int m,int n){
	return (ll)jc[m]*ny[n]%mo*ny[m-n]%mo;
}
int a[M];
int main()
{
	freopen("color.in","r",stdin);
	freopen("color.out","w",stdout);
	int n,m,mx;
	scanf("%d %d",&n,&m),mx=max(n,m);
	jc[0]=1;
	fo(i,1,mx) jc[i]=(ll)jc[i-1]*i%mo;
	ny[mx]=qpow(jc[mx],mo-2);
	fd(i,mx,1) ny[i-1]=(ll)ny[i]*i%mo;
	solve(a,n-1);
	int ans=0;
	fo(i,0,m-1) ans=pl(ans,(ll)a[i]*C(m-1,i)%mo);
	printf("%d",ans);
}

要在VS Code中使用CMake配置OpenCV C++项目,可以按照以下步骤进行操作: 1. 确保已经安装了Visual Studio Code和CMake,并将它们添加到系统的环境变量中。 2. 创建一个新的文件夹作为您的项目文件夹,并在其中创建一个CMakeLists.txt文件。在CMakeLists.txt中,输入以下内容: ```cmake cmake_minimum_required(VERSION 3.0) project(YourProjectName) find_package(OpenCV REQUIRED) add_executable(YourExecutableName main.cpp) target_link_libraries(YourExecutableName ${OpenCV_LIBS}) ``` 这个CMakeLists.txt文件指定了项目的最低CMake版本、项目名称以及要使用的OpenCV库。 3. 在项目文件夹中创建一个main.cpp文件,并编写您的OpenCV C++代码。 4. 打开Visual Studio Code,选择“文件”->“打开文件夹”,并选择您的项目文件夹。 5. 安装CMake Tools插件。在Visual Studio Code的扩展面板中搜索"CMake Tools"并安装。 6. 在Visual Studio Code的底部状态栏,找到一个齿轮图标,点击它以打开CMake Tools。 7. 在CMake Tools的侧边栏中,选择您的项目文件夹并点击“配置”。 8. 在弹出的对话框中,选择一个构建目录(可以是您项目文件夹下的子文件夹),然后选择CMake工具链。 9. 在弹出的对话框中,输入以下参数并保存: - "cmake.configureOnOpen": false - "cmake.buildDirectory": "build" 这些参数将配置CMake Tools以在打开项目时不自动运行CMake,并将生成的文件放在名为"build"的文件夹中。 10. 回到CMake Tools的侧边栏,点击“配置”按钮,然后选择“生成”按钮。这将运行CMake生成您的项目。 11. 在CMake Tools的侧边栏中,点击“构建”按钮来编译您的项目。 12. 您可以在Visual Studio Code的终端中运行您的可执行文件,或者根据需要进行调试。 这样,您就可以在VS Code中使用CMake配置OpenCV C++项目了。记得根据您的具体项目情况修改CMakeLists.txt和main.cpp文件。祝您成功!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值