首页 > 其他 > 详细

CF960G Bandit Blues

时间:2019-03-24 21:41:36      阅读:113      评论:0      收藏:0      [点我收藏+]

题目链接

题意分析

我们考虑将已经维护好了\(2∽n\)的数列现在考虑插入最小值

然后现在插入最小值\(1\)

现在我们使用\(dp(i,j)\)表示前\(i\)个数一共存在\(j\)个前缀最大值的方案数

我们如果放在开头 那么贡献就是\(dp(i-1,j-1)\)

如果放在别的位置就是\(dp(i-1,j)\)

所以

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

等一下 这就是第一类\(Strling\)

\[S(n,m)=S(n-1,m-1)+(n-1)* S(n-1,m)\]

然后我们考虑怎么计算题目要求的

首先我们考虑对于一个序列\(i\)存在\(j\)个前缀最小大值

翻转之后就是存在\(j\)个后缀最大值

所以我们考虑当前最大值\(n\)插入的位置

那么一定是左边存在\(a-1\)个前缀最大值 右边存在\(b-1\)个后缀最大值

那么答案就是

\[ans=\sum_{i=a-1}^{n-b}dp(i,a-1)* dp(n-i-1,b-1)* C_{n-1}^i\]

但是我们无须枚举

考虑当前是\(dp(n-1,a+b-2)\)

我们将最大值\(n\)插入第\(a-1\)个之后

然后剩余的\(b-1\)到后面然后翻转 就成了我们要的序列

所以就是

\[ans=dp(n-1,a+b-2)* C_{a+b-2}^{a-1}\]

关于第一类\(Strling\)

\[x(x+1)(x+2)......(x+n-1)=\sum_{i=0}^nS(n,i)x^i\]

所以我们可以使用分治\(NTT\)

CODE:

/*-------------OI使我快乐-------------*/
int n,cdy,wzy;
ll ans[20][N],key[N];
IL ll qpow(ll x,ll y)
{ll res=1;for(;y;y>>=1,x=x*x%mod) if(y&1) res=res*x%mod;return res;}
IL ll C(ll x,ll y)
{
    ll res1=1,res2=1;
    for(R ll i=x-y+1;i<=x;++i) res1=res1*i%mod;
    for(R ll i=1;i<=y;++i) res2=res2*i%mod;
    return res1*qpow(res2,mod-2)%mod;
}
IL void NTT(ll *A,int lim,int knd)
{
    for(R int i=0;i<lim;++i) if(i<key[i]) swap(A[i],A[key[i]]);
    for(R int mid=1;mid<lim;mid<<=1)
    {
        ll Wn=qpow(knd==1 ? 3:Gi,(mod-1)/(mid<<1));
        for(R int j=0;j<lim;j+=(mid<<1))
        {
            ll w=1;
            for(R int k=0;k<mid;++k,w=w*Wn%mod)
            {
                ll x=A[j+k],y=w*A[j+k+mid]%mod;
                A[j+k]=(x+y)%mod;A[j+k+mid]=(x-y+mod)%mod;
            } 
        }
    }
    if(knd==-1)
    {
        ll inv=qpow(lim,mod-2);
        for(R int i=0;i<lim;++i) A[i]=A[i]*inv%mod;
        return;
    }
}
IL void solve(int si,int le,int ri)
{
    if(le==ri) {ans[si][0]=le;ans[si][1]=1;return;} 
    int mid=(le+ri)>>1;
    solve(si+1,le,mid);
    for(R int i=0;i<=mid-le+1;++i) ans[si][i]=ans[si+1][i];
    solve(si+1,mid+1,ri);
    
    int all=0,lim=0;
    for(lim=1;lim<=(ri-le+1)+2;lim<<=1) ++all;
    for(R int i=0;i<lim;++i) key[i]=((key[i>>1]>>1)|((i&1)<<(all-1)));
    for(R int i=mid-le+2;i<lim;++i) ans[si][i]=0;
    for(R int i=ri-mid+1;i<lim;++i) ans[si+1][i]=0;
    NTT(ans[si],lim,1);NTT(ans[si+1],lim,1);
    for(R int i=0;i<lim;++i) ans[si][i]=ans[si][i]*ans[si+1][i]%mod;
    NTT(ans[si],lim,-1);
}
int main()
{
//  freopen("lzxkj.in","r",stdin);
//  freopen("lzxkj.out","w",stdout);
    read(n);read(cdy);read(wzy);
    if(!cdy||!wzy||cdy+wzy-1>n) {puts("0");return 0;}
    if(n==1) {puts("1");return 0;}
    solve(0,0,n-2);
    printf("%lld\n",ans[0][cdy+wzy-2]*C(cdy+wzy-2,cdy-1)%mod);
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

HEOI 2019 RP++

CF960G Bandit Blues

原文:https://www.cnblogs.com/LovToLZX/p/10590502.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!