zoukankan      html  css  js  c++  java
  • CF960G

    传送门

    (dp[i][j])(i)个数字的排列,有(A=j)的方案数

    假设新加入的数字是最小的,考虑它放在哪里得到

    [dp[i][j]=dp[i-1][j-1]+(i-1)*dp[i-1][j] ]

    共有(i)个插入位置,放在队首的时候会使(j+1)

    发现(dp)数组就是第一类斯特林数

    因为(n)的前后都没有比它大的数字,所以(n)一个是第(a)(A)和第(b)(B),枚举(n)的位置得到

    [ans=sumlimits_{i=1}^{n}egin{bmatrix}i-1\a-1end{bmatrix}*egin{bmatrix}n-i\b-1end{bmatrix}*dbinom{n-1}{i-1} ]

    考虑组合意义:相当于在(n-1)个数字中选择(i-1)个结成(a-1)个环,在剩下的(n-i)个数字中结成(b-1)个环的方案数

    等价于在把(n-1)个数字结成(a+b-2)个环,再从环中选择(a-1)

    [ans=egin{bmatrix}n-1\a+b-2end{bmatrix}dbinom{a+b-2}{a-1} ]

    虽然没有快速求单个第一类斯特林数的方案,但是时间复杂度允许(O(nlogn)),所以可以求一行或一列

    #include<bits/stdc++.h>
    using namespace std;
    namespace red{
    #define int long long
    #define ls(p) (p<<1)
    #define rs(p) (p<<1|1)
    #define lowbit(i) ((i)&(-i))
    	inline int read()
    	{
    		int x=0;char ch,f=1;
    		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    		if(ch=='-') f=0,ch=getchar();
    		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    		return f?x:-x;
    	}
    	const int N=524292,p=998244353;
    	int n,t1,t2,ans;
    	int fac[N],ifac[N],inv[N],pos[N];
    	int f[N],g[N];
    	inline void init(int n)
    	{
    		inv[1]=1;
      		for(int i=2;i<=n;++i) inv[i]=(-(p/i)*inv[p%i]%p+p)%p;
      		fac[0]=ifac[0]=1;
    		for(int i=1;i<=n;++i) fac[i]=fac[i-1]*i%p,ifac[i]=ifac[i-1]*inv[i]%p;
    	}
    	inline int fast(int x,int k)
    	{
    		int ret=1;
    		while(k)
    		{
    			if(k&1) ret=ret*x%p;
    			x=x*x%p;
    			k>>=1;
    		}
    		return ret;
    	}
    	inline void ntt(int limit,int *a,int inv)
    	{
    		for(int i=1;i<limit;++i)
    			if(i<pos[i]) swap(a[i],a[pos[i]]);
    		for(int mid=1;mid<limit;mid<<=1)
    		{
    			int Wn=fast(3,(p-1)/(mid<<1));
    			for(int r=mid<<1,j=0;j<limit;j+=r)
    			{
    				int w=1;
    				for(int k=0;k<mid;++k,w=w*Wn%p)
    				{
    					int x=a[j+k],y=w*a[j+k+mid]%p;
    					a[j+k]=(x+y)%p;
    					a[j+k+mid]=(x-y+p)%p;
    				}
    			}
    		}
    		if(inv) return;
    		inv=fast(limit,p-2);reverse(a+1,a+limit);
    		for(int i=0;i<limit;++i) a[i]=a[i]*inv%p;
    	}
    	inline void offset(int *f,int n,int c,int *g)
    	{
    		static int a[N],b[N];
    		int limit=1,len=0;
    		while(limit<=n*2) limit<<=1,++len;
    		for(int i=1;i<limit;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<(len-1));
    		for(int i=0;i<=n;++i) a[i]=fac[i]*f[i]%p;
    		int tmp=1;
    		for(int i=0;i<=n;++i,tmp=tmp*c%p) b[n-i]=tmp*ifac[i]%p;
    		for(int i=n+1;i<limit;++i) a[i]=b[i]=0;
    		ntt(limit,a,1);ntt(limit,b,1);
    		for(int i=0;i<limit;++i) a[i]=a[i]*b[i]%p;
    		ntt(limit,a,0);
    		for(int i=0;i<=n;++i) g[i]=a[i+n]*ifac[i]%p;
    	}
    	inline void solve(int *f,int n)
    	{
    		if(n==0) return(void)(f[0]=1);
    		static int a[N],b[N];
    		int m=n>>1;
    		solve(f,m);
    		offset(f,m,m,a);
    		int limit=1,len=0;
    		while(limit<=n) limit<<=1,++len;
    		for(int i=1;i<limit;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<(len-1));
    		for(int i=0;i<=m;++i) b[i]=f[i];
    		for(int i=m+1;i<limit;++i) a[i]=b[i]=0;
    		ntt(limit,a,1);ntt(limit,b,1);
    		for(int i=0;i<limit;++i) a[i]=a[i]*b[i]%p;
    		ntt(limit,a,0);
    		if(n&1)//乘一个(x+n-1)
    		{
    			for(int i=0;i<=n;++i)
    				f[i]=((i?a[i-1]:0)+(n-1)*a[i])%p;
    		}
    		else
    		{
    			for(int i=0;i<=n;++i)
    				f[i]=a[i];
    		}
    	}
    	inline int C(int n,int m)
    	{
    		if(n<m) return 0;
    		return fac[n]*ifac[m]%p*ifac[n-m]%p;
    	}
    	inline void main()
    	{
    		n=read()-1,t1=read()-1,t2=read()-1;
    		init(n<<1);
    		solve(f,n);
    		ans=(f[t1+t2]+p)%p;
    		ans=ans*C(t1+t2,t1)%p;
    		printf("%lld
    ",ans);
    	}
    }
    signed main()
    {
    	red::main();
    	return 0;
    }
    
  • 相关阅读:
    SpringMVC之数据处理及跳转
    SpringMVC之控制器Controller和RestFul风格
    第一个SpringMVC程序
    什么是SpringMVC
    Spring声明式事务
    【嘎】字符串-反转字符串
    【嘎】字符串-字符串中的单词数
    【嘎】二叉树-226. 翻转二叉树
    【嘎】数组-面试题 01.07. 旋转矩阵-看题解
    【嘎】字符串-统计位数为偶数的数字
  • 原文地址:https://www.cnblogs.com/knife-rose/p/13054957.html
Copyright © 2011-2022 走看看