• Codeforces 960G. Bandit Blues


    Description

    你需要构造一个长度为 (n) 的排列 , 使得一个数作为前缀最大值的次数为 (A) , 作为后缀最大值的次数为 (B) , 求满足要求的排列个数 .
    题面

    Solution

    (FJOI) 建筑师 .
    (n)(1) 依次加入 , 对于 (n) ,对 (A,B) 的出现次数都会贡献 (1) .
    剩下的数 , 如果放在左边则对 (A) 有贡献 , 放在右边则对 (B) 有贡献 , 放在中间则没有贡献 .
    我们从组合意义上分析 , 那么相当于是操作 (n-1) 轮 , 每轮可以选择 从 ((0,0)) 向走 ((A-1,B-1)) 一步或者停顿的方案数 .
    ((0,0)) 走向 ((A-1,B-1)) 的不同方案数为 (C(A+B-2,A-1))
    并且还要求出分配停顿的位置(确定每个位置停了几次)的不同方案数 .
    这个可以 (DP) 设前 (i) 次操作 , 走了 (j) 步的方案数, (f[i][j]=f[i-1][j-1]+f[i-1][j]*(i-1)) , 这个东西就等于第一类斯特林数 .
    由于(S(n,m))等于 (P(x,n)) 的第 (x^m) 项系数 , 就可以对应一个上升幂的 (x^m) 项系数.
    可以分治+(NTT) 合并出一个长度为 (n) 的多项式 , 就可以求出第一类斯特林数的某一行了 .

    #include<bits/stdc++.h>
    using namespace std;
    template<class T>void gi(T &x){
    	int f;char c;
    	for(f=1,c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
    	for(x=0;c<='9'&&c>='0';c=getchar())x=x*10+(c&15);x*=f;
    }
    const int N=4e5+10,mod=998244353;
    inline int qm(int x,int k){
    	int sum=1;
    	for(;k;k>>=1,x=1ll*x*x%mod)if(k&1)sum=1ll*sum*x%mod;
    	return sum;
    }
    int n,a[20][N],R[N],L=0;
    inline int C(int n,int m){
    	if(n<m || n<0 || m<0)return 0;
    	int ret=1,I=1;
    	for(int i=1;i<=m;i++)ret=1ll*ret*(n-i+1)%mod,I=1ll*I*i%mod;
    	return 1ll*ret*qm(I,mod-2)%mod;
    }
    inline void NTT(int *A){
    	for(int i=0;i<n;i++)if(i<R[i])swap(A[i],A[R[i]]);
    	for(int i=1;i<n;i<<=1){
    		int t0=qm(3,(mod-1)/(i<<1)),x,y;
    		for(int j=0;j<n;j+=i<<1){
    			int t=1;
    			for(int k=0;k<i;k++,t=1ll*t*t0%mod){
    				x=A[j+k];y=1ll*A[j+k+i]*t%mod;
    				A[j+k]=(x+y)%mod;A[j+k+i]=(x-y+mod)%mod;
    			}
    		}
    	}
    }
    inline void mul(int *A,int *B){
    	NTT(A);NTT(B);
    	for(int i=0;i<n;i++)A[i]=1ll*A[i]*B[i]%mod;
    	NTT(A);reverse(A+1,A+n);
    	for(int i=0,t=qm(n,mod-2);i<n;i++)A[i]=1ll*A[i]*t%mod;
    }
    inline void solve(int l,int r,int d){
    	if(l==r){a[d][0]=l;a[d][1]=1;return ;}
    	int mid=(l+r)>>1,m=r-l+1;
    	solve(l,mid,d+1);
    	for(int i=0;i<=m;i++)a[d][i]=a[d+1][i];
    	solve(mid+1,r,d+1);
    	for(n=1,L=0;n<=m;n<<=1)L++;
    	for(int i=mid-l+2;i<n;i++)a[d][i]=0;
    	for(int i=r-mid+1;i<n;i++)a[d+1][i]=0;
    	for(int i=0;i<n;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
    	mul(a[d],a[d+1]);
    }
    int A,B;
    int main(){
      freopen("pp.in","r",stdin);
      freopen("pp.out","w",stdout);
      cin>>n>>A>>B;
      if(n==1){
    	  if(A+B-2>=0)puts("1");else puts("0");
    	  exit(0);
      }
      solve(0,n-2,0);
      cout<<1ll*a[0][A+B-2]*C(A+B-2,A-1)%mod;
      return 0;
    }
    
    
  • 相关阅读:
    套接字描述符在多进程和多线程下的共享
    广播和多播
    原始套接字和数据链路层访问
    Libevent:11使用Libevent的DNS上层和底层功能
    Lib1vent:10链接监听器接受TCP链接
    Libevent:9Evbuffers缓存IO的实用功能
    Libevent:7Bufferevents基本概念
    python生成url测试用例
    OMD开源监控软件
    iptable防范ddos攻击
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9236119.html
Copyright © 2020-2023  润新知