• 【CF960G】Bandit Blues(第一类斯特林数)


    点此看题面

    • 求有多少长度为(n)的排列,满足它有(A)个前缀最大值和(B)个后缀最大值。
    • (nle10^5)

    第一类斯特林数

    显然,序列中的最大值必然既是前缀最大值又是后缀最大值,而它左右区间的数则形成了相对独立的两部分。

    我们把每个前缀最大值及它到下一个前缀最大值之前的数看成一部分,每个后缀最大值及它到上一个后缀最大值之前的数也看成一部分。

    后者可以认为是由前者翻转得到的,所以这两种情况应该可以类似讨论。

    然后我们就发现除去最大值之后剩余的(n-1)个数被我们划分成了(a+b-2)个部分,每个部分可自己任定相对顺序,但又必须以这一部分的最大值作为开头。

    所以说,每一部分可以看成一个环,那么方案数就应该是(S_1(n-1,a+b-2))

    而左右两块中,每一块的环都必须要满足最大值递增,相对顺序是固定的,因此只要考虑把这些环分成两部分的方案数,也就是(C_{a+b-2}^{a-1})

    综上,答案就应该是:

    [S_1(n-1,a+b-2) imes C_{a+b-2}^{a-1} ]

    快速求斯特林数(伪)

    只会(O(nlog^2n))的屑做法,但也足以通过此题了。。。

    考虑第一类斯特林数的递推式:

    [S_1(n,m)=S_1(n-1,m-1)+S_1(n-1,m) imes(n-1) ]

    我们把每一行的斯特林数看成一个多项式(第(n)行用(S_1[n])来表示),那么上式就可以写成:

    [S_{1}[n]=S_1[n-1] imes(x+n-1) ]

    简单地说,这也就是:

    [S_1[n]=prod_{i=1}^n(x+i-1) ]

    显然这个式子可以直接分治(NTT),那么就结束了。

    代码:(O(nlog^2n))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 200000
    #define X 998244353
    using namespace std;
    int n,A,B;I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
    namespace Poly
    {
    	#define PR 3
    	int P,L,A[N<<1],B[N<<1],R[N<<1];I void T(int* s,CI op)
    	{
    		RI i,j,k,x,y,U,S;for(i=0;i^P;++i) i<R[i]&&(swap(s[i],s[R[i]]),0);
    		for(i=1;i^P;i<<=1) for(U=QP(QP(PR,op),(X-1)/(i<<1)),j=0;j^P;j+=i<<1) for(S=1,
    			k=0;k^i;++k,S=1LL*S*U%X) s[j+k]=((x=s[j+k])+(y=1LL*S*s[i+j+k]%X))%X,s[i+j+k]=(x-y+X)%X;
    	}
    	int ct,f[50][N+5];I void Solve(CI l,CI r,CI rt)//分治NTT
    	{
    		if(l==r) return (void)(f[rt][0]=l-1,f[rt][1]=1);//边界
    		RI i,mid=l+r>>1,lc=++ct,rc=++ct;Solve(l,mid,lc),Solve(mid+1,r,rc);//递归
    		P=1,L=0;W(P<=2*(r-l+1)) P<<=1,++L;for(i=0;i^P;++i) A[i]=B[i]=0,R[i]=(R[i>>1]>>1)|((i&1)<<L-1);
    		for(i=0;i<=mid-l+1;++i) A[i]=f[lc][i];for(i=0;i<=r-mid;++i) B[i]=f[rc][i];
    		for(T(A,1),T(B,1),i=0;i^P;++i) A[i]=1LL*A[i]*B[i]%X;//把左右区间的多项式卷起来
    		RI t=QP(P,X-2);for(T(A,X-2),i=0;i<=r-l+1;++i) f[rt][i]=1LL*A[i]*t%X;ct-=2;
    	}
    }
    I int S1(CI n,CI m) {return n>m?(Poly::Solve(1,n,0),Poly::f[0][m]):n==m;}//第一类斯特林数
    I int C(CI n,CI m) {RI i,t=1;for(i=m+1;i<=n;++i) t=1LL*t*i%X*QP(i-m,X-2)%X;return t;}//组合数
    int main()
    {
    	if(scanf("%d%d%d",&n,&A,&B),!A||!B) return puts("0"),0;//不可能为0,因为整个序列的最大值必然是前后缀最大值
    	return printf("%lld
    ",1LL*S1(n-1,A+B-2)*C(A+B-2,A-1)%X),0;//根据答案式计算
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    虚拟机(VM) windows server2003 里终于有声音了 Kenny
    web 打印 webrower 控件的ExecWB 及 兼容IE6 IE7 IE8 打印 办法 Kenny
    周三了,工作状态还没调回来 Kenny
    [转]javascript 异步调用 后台.cs里的方法 PageMethods如何使用 Kenny
    FLASHSPI
    函数指针的使用:使程序跳转到Flash指定位置
    关于内存对齐
    SD卡实验:神舟IV
    LCD 横屏竖屏
    全局变量、局部变量、静态全局变量、静态局部变量的区别
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/CF960G.html
Copyright © 2020-2023  润新知