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,然后就可以很方便地转移了。

  • 相关阅读:
    SPSS分类分析:决策树
    单例设计模式
    设计模式
    java.lang.NoClassDefFoundError: org/apache/zookeeper/proto/SetWatches
    AngularJs中Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.3.15/
    如何在linux环境下配置环境变量
    MQ的面试题
    VUE框架
    SQL中and和or的区别是?
    Git的工作流程
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8576598.html
Copyright © 2011-2022 走看看