zoukankan      html  css  js  c++  java
  • 牛客练习赛71 C- 数学考试 dp

    牛客练习赛71 C- 数学考试

    题意

    (1sim n) 的排列,有 (m) 个限制条件,第(i)个限制条件 (p_i) 表示前 (p_i) 个数不能是 (1sim p_i) 的排列,求符合要求的排列的个数。 答案对 20000311 取模。

    (nle 2000,m,p_i<n)

    做法1

    (dp[i][j])为满足限制的情况下放好了排列的前(i)个数且最大值为(j)的方案数,转移如下:

    • (i=j=p_k,k in [1,m]),说明这一位有限制(dp[i][j]=0)
    • 否则,(dp[i][j]=sum_{k=1}^{j-1}dp[i-1][k]+dp[i-1][j] cdot (j-i+1)),表示若(k<j),那么第(i)位只能放一种数(j),若(k=j),第(i)位可以放(j-i+1)种数,前面的部分可以前缀和优化。

    复杂度为(O(n^2))

    做法2

    (dp[i])为放置前(p[i])个数满足前(i-1)个限制,但是不满足第(i)个限制的方案数。

    (dp[i]=p[i]!-sum_{j=1}^{i-1}dp[j] cdot (p[i]-p[j])!)(p[i]!)为放置前(p[i])个数不满足第(i)个限制的方案数,对于(j<i),减去放置前(p[i])个数满足前(j-1)个限制不满足第(j)个限制的所有方案数(dp[j]cdot (p[i]-p[j])!)((p[i]-p[j])!)表示从(p[j])(p[i])的位置可以随意放,这样就可以不重复的计算出(dp[i]),在最后加一个(p[i]=n)的限制,最后输出(dp[m])即可。

    复杂度为(O(m^2))

    Code1

    #include <bits/stdc++.h>
    using namespace std;
    const int N=2e3+10;
    const int mod=20000311;
    typedef long long ll;
    ll dp[N][N],f[N];
    int n,m,p[N];
    int main()
    {
        scanf("%d%d",&n,&m);
        dp[0][0]=1;
        for(int i=1;i<=m;i++){
            int x;
            scanf("%d",&x);
            p[x]=1;
        }
        for(int i=1;i<=n;i++){
            memset(f,0,sizeof f);
            f[i-1]=dp[i-1][i-1];
            for(int j=i;j<=n;j++) f[j]=(f[j-1]+dp[i-1][j])%mod;
            for(int j=i;j<=n;j++){
                if(i==j&&p[j]) continue;
                (dp[i][j]+=f[j-1]%mod)%=mod;
                (dp[i][j]+=dp[i-1][j]*(j-i+1)%mod)%=mod;
            }
        }
        printf("%lld
    ",dp[n][n]);
        return 0;
    }
    

    Code2

    #include<bits/stdc++.h>
    #define rep(i,x,n) for(int i=x;i<=n;i++)
    #define per(i,n,x) for(int i=n;i>=x;i--)
    #define ll long long
    using namespace std;
    const int mod=20000311;
    const int N=1e5+10;
    int n,m;
    int p[N],f[N],dp[N];
    int main(){
        scanf("%d%d",&n,&m);
        rep(i,1,m){
            scanf("%d",&p[i]);
        }
        f[0]=1;
        rep(i,1,n) f[i]=1ll*f[i-1]*i%mod;
        p[++m]=n;
        sort(p+1,p+m+1);
        for(int i=1;i<=m;i++){
            dp[i]=f[p[i]];
            for(int j=1;j<i;j++) dp[i]=(dp[i]+mod-1ll*dp[j]*f[p[i]-p[j]]%mod)%mod;
        }
        printf("%d
    ",dp[m]);
        return 0;
    }
    
  • 相关阅读:
    密码学浅析
    FireWall Mark + LVS
    tcp/ip首部
    iptables(二)网络防火墙
    BIND服务
    LVS(一)
    QQ、微信消息轰炸
    LVS四种模型(二)
    安装和克隆
    压缩和打包
  • 原文地址:https://www.cnblogs.com/xyq0220/p/13812526.html
Copyright © 2011-2022 走看看