zoukankan      html  css  js  c++  java
  • 【CodeForces】889 C. Maximum Element 排列组合+动态规划

    【题目】C. Maximum Element

    【题意】给定n和k,定义一个排列是好的当且仅当存在一个位置i,满足对于所有的j=[1,i-1]&&[i+1,i+k]有a[i]>a[j],求长度为n的好的排列数。n<=10^6。

    【算法】排列组合+动态规划

    【题解】设D(n)表示长度为n且满足a[n]=n的好的排列数,考虑这样的一个排列w。

    如果数字n-1的位置j<n-k,那么显然这是一个好的排列。

    如果数字n-1的位置j>=n-k,那么位置j前的数字一定<n-1,那么1~j形成好的排列的方案实际上是D(j)。

    $$D(n)=(n-k-1)*(n-2)!+sum_{j=n-k}^{n-1}D(j)*A(n-2,n-j-1)$$

    第一部分:数字n-1有n-k-1个位置,每个位置固定后可以进行全排列即(n-2)!

    第二部分:枚举数字n-1的位置,固定后后面的n-j-1个位置可以从除了n和n-1的数字中任意取数填满,剩下的数字当成1~j构成D(j)。

    化简后得到:

    $$D(n)=(n-k-1)*(n-2)!+(n-2)!sum_{j=n-k}^{n-1}frac{D(j)}{(j-1)!}$$

    边算前缀和即可。

    最后,枚举答案中n的位置(因为数字n后面的位置没有意义),那么:

    $$ans=sum_{i=1}^{n}D(j)*A(n-1,n-i)=(n-1)!*sum_{i=1}^{n}frac{D(j)}{(j-1)!}$$

    复杂度O(n)。

    #include<cstdio>
    const int maxn=1000010,MOD=1e9+7;
    int n,k,fac[maxn],fav[maxn],D[maxn],h[maxn];
    void gcd(int a,int b,int& x,int& y){if(!b){x=1;y=0;}else{gcd(b,a%b,y,x);y-=x*(a/b);}}
    int inv(int a){int x,y;gcd(a,MOD,x,y);return (x%MOD+MOD)%MOD;}
    int main(){
        scanf("%d%d",&n,&k);
        fac[0]=1;
        for(int i=1;i<=n;i++)fac[i]=1ll*fac[i-1]*i%MOD,fav[i]=inv(fac[i]);
        for(int i=1;i<=n;i++)if(i>k){
             D[i]=1ll*fac[i-2]*((i-k-1)+h[i-1]-h[i-k-1]+MOD)%MOD;
             h[i]=(h[i-1]+1ll*D[i]*fav[i-1])%MOD;
        }
        printf("%lld",1ll*h[n]*fac[n-1]%MOD);
        return 0;
    }
    View Code

    排列组合相关的DP需要记住一件事:1~n的排列代表的是n个数的大小关系的排列,不一定需要1~n,然后就可以很方便地转移了。

  • 相关阅读:
    nginx 过滤了自定义的请求头参数
    Mysql5.7查看已经执行的sql语句
    Reids5 持久化
    JS 格式化时间,转成 几天前,几个月前
    个人小镜像站点
    记录一次清理Redis 病毒程序 kdevtmpfsi
    laravels 热重启
    Redis 布隆器安装和简单实现
    Redis Zset类型跳跃表算法实现(JAVA)
    Redis5 基于Lua实现分布式排它锁
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8576598.html
Copyright © 2011-2022 走看看