P2401 不等数列

原题链接 https://www.luogu.org/problemnew/show/P2401

第一眼看觉得是暴力,草草得估了一下下时间复杂度:O(n * n!),显然不行。

考虑DP。

我们设:dp [ i ][ j ] 为序列中有 i 个数,其中满足 j 对 '<' 关系;

考虑边界情况

当我们的序列是从大到小排列时,无论序列里有多少个数,都是满足 '>' 关系,不满足 '<'关系;

换句话说,也就是使得序列全都不满足 '<' 关系的情况也就一种排列;

那么我们就得出了边界条件:

    for(int i=1;i<=n;i++)     //当前序列里有i个数 
        dp[i][0]=1;           //只能从大到小排好,就一种情况

考虑状态转移方程

假设我们的序列里已经排好了 i-1 个数,我们当前正在插入第 i 个数,考虑我们可以往哪里插入:

加入我们已经将X1~X5排好了,它们的关系是这样的:

(A)现在我们考虑插入一个X6,我们可以插在这个序列的最后边,那么就会变成这样子:

(B)当然我们也可以插入到最前面,那么就是介个样子:

然后就是插在序列中间的情况,还要细分:

(C)1.插在小于号的位置:

(D)2.插在大于号的位置:

我们发现(A)和(D)这两种插法都会使得原序列多一个小于号,而(B)和(C)不会使原序列多一个小于号。

所以我们dp [ i ][ j ] 就可以从 dp [ i-1 ][ j-1 ] 和 dp [ i-1 ][ j ] 转移过来了,分别对应的是增加一个小于号和不增加小于号的情况;

怎么转移呢?先考虑 dp [ i-1 ][ j-1 ] 怎么转移过来: 

序列中已经有了 i-1 个数,说明有 i-2 个符号('<' 或 '>'),其中有 j-1 个'<',那不就说明有(i-2)-(j-1)= i-j-1 个 '>',我们要使这个数按照(A)和(D)的方式插入才能转移到 dp [ i ][ j ],所以考虑到我们合法的插入位置有(i-j-1)+1 = i-j 个,根据乘法计数原理可知:产生的方案数为 dp [ i-1 ][ j-1 ] *(i-j);

dp [ i-1 ][ j ]同理,我们要将其按照(B)和(C)的方式插入,i-1 个数,j 个'<',合法的插入位置有 j+1 个,根据乘法技术原理可知:产生的方案数为 dp [ i-1 ][ j ] *(j+1);

考试时的AC代码:

#include<iostream>
#include<cstdio>
using namespace std;
int read()
{
    char ch=getchar();
    int a=0,x=1;
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') x=-x;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        a=(a<<1)+(a<<3)+(ch-'0');
        ch=getchar();
    }
    return a*x;
}
const int mod=2015;
int n,k;
int dp[1010][1010];
//DP吧这题 
//与其一个一个排序,不如看做是好几个数一个一个往里插入
//dp[i][j]:序列里有i个数,且数列里已经有j个'<'的方案数 
//最后答案就是:dp[n][k] 
int main()
{
    //freopen("num.in","r",stdin);
    //freopen("num.out","w",stdout);
    n=read();k=read();
    for(int i=1;i<n;i++)      //当前序列里有 
    {
        dp[i][0]=1;           //边界情况,只能从大到小排好
        for(int j=0;j<i;j++)  //枚举序列里有多少个小于号 
        {
            dp[i+1][j]=(dp[i+1][j]+dp[i][j]*(j+1)%mod)%mod;   //有(j+1)个空插入后使得原序列的小于号个数不变
            dp[i+1][j+1]=(dp[i+1][j+1]+dp[i][j]*(i-j)%mod)%mod; //i个数,只有i-1个符号,其中小于号有j个,大于号就有i-1-j,再加上最右边还有一个空 
        } 
    }
    printf("%d",dp[n][k]%mod);
    return 0;
} 
原文地址:https://www.cnblogs.com/xcg123/p/11166662.html