• 解题:CF960G Bandit Blues & FJOI 2016 建筑师


    题面1 题面2

    两个题推导是一样的,具体实现不一样,所以写一起了,以FJOI 2016 建筑师 的题面为标准

    前后在组合意义下一样,现在只考虑前面,可以发现看到的这a个建筑将这一段划分成了a-1个区间,区间里的数随意填。

    看起来可以用组合数算,但是还要考虑看到的建筑,所以我们把每个建筑和它后面这段区间合起来看。设区间的长度是len,这就是一个len+1个数的圆排列(等于len!,相当于固定一个开头后面随便排)

    这样考虑前后就是将n-1个数划分为a+b-2个全排列,n-1是因为最高的那个在两边都没被算进去,是第一类斯特林数。同时a+b-2个圆排列之间还要选出来a-1个放前面,乘上组合数即可。现在关键是如何求第一类斯特林数。

    FJOI那道题n*k不是很大,可以直接$O(nk)$递推,边界条件是$S[0][0]=1$,转移是$S[i][j]=S[i-1][j-1]+S[i-1][j]*(i-1)$

    CF那道题只有一次询问,但是n,k都很大,我们考虑第一类斯特林数在第一维固定下的生成函数:$G(x)=prodlimits_{i=0}^{n-1}(x+i)$,x是从$s[i-1][j-1]$来的,i-1是从$s[i-1][j]*(i-1)$来的。用分治NTT优化

    Code1

      1 //Simple NTT
      2 #include<cmath>
      3 #include<cstdio>
      4 #include<cctype>
      5 #include<cstring>
      6 #include<algorithm>
      7 #define vint vector<int>
      8 using namespace std;
      9 const int N=2000006,mod=998244353;
     10 int fac[N],inv[N],rev[N];
     11 int aa[N],bb[N],pw[30][2];
     12 int a,b,n,l1,l2,G,Gi,Ni; vint stl;
     13 int Qpow(int x,int k)
     14 {
     15     if(k==1) return x;
     16     int tmp=Qpow(x,k/2);
     17     return k%2?1ll*tmp*tmp%mod*x%mod:1ll*tmp*tmp%mod;
     18 }
     19 int C(int a,int b)
     20 {
     21     return 1ll*fac[a]*inv[b]%mod*inv[a-b]%mod;
     22 }
     23 void SPJ()
     24 {
     25     if(!a||!b||n-1<a+b-2) printf("0"),exit(0);
     26     if(n==1) printf("1"),exit(0);
     27 }
     28 void Pre()
     29 {
     30     fac[0]=inv[0]=1,G=3,Gi=Qpow(G,mod-2);
     31     for(int i=1;i<=24;i++)
     32     {
     33         pw[i][0]=Qpow(G,(mod-1)/(1<<i));
     34         pw[i][1]=Qpow(Gi,(mod-1)/(1<<i));
     35     }
     36     for(int i=1;i<=a+b;i++) fac[i]=1ll*fac[i-1]*i%mod;
     37     inv[a+b]=Qpow(fac[a+b],mod-2);
     38     for(int i=a+b-1;i;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
     39 }
     40 void Prework(vint &a,vint &b)
     41 {
     42     register int i; 
     43     l1=a.size()-1,l2=b.size()-1;
     44     l1+=l2,l2=1; while(l2<=l1) l2<<=1;
     45     a.resize(l2),b.resize(l2);
     46     for(i=0;i<=l2;i++) aa[i]=a[i];
     47     for(i=0;i<=l2;i++) bb[i]=b[i];
     48     for(i=1;i<l2;i++)
     49         rev[i]=(rev[i>>1]>>1)+(i&1)*(l2>>1);
     50 }
     51 void Trans(int *arr,int len,int typ)
     52 {
     53     register int i,j,k;
     54     for(i=0;i<len;i++)
     55         if(rev[i]>i) swap(arr[rev[i]],arr[i]);
     56     for(i=2;i<=len;i<<=1)
     57     {
     58         int lth=i>>1,ort=pw[(int)log2(i)][typ==-1];
     59         for(j=0;j<len;j+=i)
     60         {
     61             int ori=1,tmp;
     62             for(k=j;k<j+lth;k++,ori=1ll*ori*ort%mod)
     63             {
     64                 tmp=1ll*ori*arr[k+lth]%mod;
     65                 arr[k+lth]=(arr[k]-tmp+mod)%mod;
     66                 arr[k]=(arr[k]+tmp)%mod;
     67             }
     68         }
     69     }
     70     if(typ==-1)
     71     {
     72         int Ni=Qpow(len,mod-2);
     73         for(i=0;i<=len;i++)
     74             arr[i]=1ll*arr[i]*Ni%mod;
     75     }
     76 }
     77 vint NTT(vint a,vint b)
     78 {
     79     Prework(a,b);
     80     Trans(aa,l2,1),Trans(bb,l2,1);
     81     for(int i=0;i<l2;i++) aa[i]=1ll*aa[i]*bb[i]%mod;
     82     Trans(aa,l2,-1);
     83     vint ret; ret.clear();
     84     for(int i=0;i<l2;i++) ret.push_back(aa[i]);
     85     return ret;
     86 }
     87 vint CDQ(int l,int r)
     88 {
     89     if(l==r) return {l,1};
     90     else
     91     {
     92         int mid=(l+r)/2;
     93         vint a1=CDQ(l,mid),a2=CDQ(mid+1,r);
     94         return NTT(a1,a2);
     95     }
     96 }
     97 int main()
     98 {
     99     scanf("%d%d%d",&n,&a,&b);
    100     SPJ(),Pre(),stl=CDQ(0,n-2);
    101     printf("%d",1ll*C(a+b-2,a-1)*stl[a+b-2]%mod);
    102     return 0;
    103 }
    View Code

    Code2

     1 #include<cmath>
     2 #include<cstdio>
     3 #include<cctype>
     4 #include<cstring>
     5 #include<algorithm>
     6 using namespace std;
     7 const int N=50006,M=405,mod=1e9+7;
     8 int fac[N],inv[N],S[N][M];
     9 int a,b,n,T,l1,l2,G,Gi,Ni; 
    10 int Qpow(int x,int k)
    11 {
    12     if(k==1) return x;
    13     int tmp=Qpow(x,k/2);
    14     return k%2?1ll*tmp*tmp%mod*x%mod:1ll*tmp*tmp%mod;
    15 }
    16 int C(int a,int b)
    17 {
    18     return 1ll*fac[a]*inv[b]%mod*inv[a-b]%mod;
    19 }
    20 bool SPJ()
    21 {
    22     if(!a||!b||n-1<a+b-2) 
    23         {puts("0"); return false;}
    24     if(n==1)     
    25         {puts("1"); return false;}
    26     return true;
    27 }
    28 void Pre()
    29 {
    30     register int i,j;
    31     fac[0]=inv[0]=1,S[0][0]=1;
    32     for(i=1;i<=1000;i++) fac[i]=1ll*fac[i-1]*i%mod;
    33     inv[1000]=Qpow(fac[1000],mod-2);
    34     for(i=999;i;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
    35     for(i=1;i<=50000;i++)
    36         for(j=1;j<=400;j++)
    37             S[i][j]=(S[i-1][j-1]+1ll*(i-1)*S[i-1][j]%mod)%mod;
    38 }
    39 int main()
    40 {
    41     Pre();
    42     scanf("%d",&T);
    43     while(T--) 
    44     {
    45         scanf("%d%d%d",&n,&a,&b);
    46         if(SPJ()) printf("%lld
    ",1ll*C(a+b-2,a-1)*S[n-1][a+b-2]%mod);
    47     }
    48     return 0;
    49 }
    View Code
  • 相关阅读:
    拥抱webpack4,有效缩减构建时间57%+
    可能是最详细的UMD模块入门指南
    Chrome远程调试手机端UC浏览器
    sea.js的同步魔法
    在Linux和Windows系统中输出目录结构
    从部署上做到前后端分离
    一种在地图中处理曲线的通用方法
    vue项目中引入iconfont
    前端路上的自我怀疑----------自我突破
    表格布局----基于bootstrap样式 布局
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/10409592.html
Copyright © 2020-2023  润新知