• 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;
    }
    
    
  • 相关阅读:
    BOI 2002 双调路径
    BOI'98 DAY 2 TASK 1 CONFERENCE CALL Dijkstra/Dijkstra+priority_queue/SPFA
    USACO 2013 November Contest, Silver Problem 2. Crowded Cows 单调队列
    BOI 2003 Problem. Spaceship
    USACO 2006 November Contest Problem. Road Blocks SPFA
    CEOI 2004 Trial session Problem. Journey DFS
    USACO 2015 January Contest, Silver Problem 2. Cow Routing Dijkstra
    LG P1233 木棍加工 动态规划,Dilworth
    LG P1020 导弹拦截 Dilworth
    USACO 2007 February Contest, Silver Problem 3. Silver Cow Party SPFA
  • 原文地址:https://www.cnblogs.com/Yuzao/p/9236119.html
Copyright © 2020-2023  润新知