P2401 不等数列

P2401 不等数列

题解

DP大法好啊,可我不会推啊

暴搜可海星啊,可惜暴30啊

打表找龟绿啊,也没推出来啊

 

设置状态

我们设置一个数组  f[ i ][ j ] 表示前 i 个数其中有 j 个 ‘<’ 的方案数

考虑我们在要放第 i 个数的时候,前 i -1 个数已经放好了,考虑第 i 个数放在哪里??

 

 

由于我们是把数字 1~n  逐个排起来的,所以当前手中的数字一定比之前排好的数字都要大,然后当前手中的数字可以放在队首,队尾,或是任意两个数中间

 

下面分类讨论:

(1)数字 i 放在队首,会增加一个 '>'

(2)数字 i 放在队尾,会增加一个 '<'

(3)数字 i 放在一个 '<' 后面,会增加一个 '>'

         PS:也就是  a<b ,放进去 c ,变成 a<c>b

(4)数字 i 放在一个 '>' 前面,会增加一个 '<'

         PS:也就是  b>a ,放进去 c ,变成 b<c>a

 

所以 f[ i ][ j ] 可能是由 f[ i-1 ][ j ] ( '<' 不增加)转移过来,也有可能是由 f[ i-1 ][ j-1 ] ('<' 增加)转移过来(加法分类原理)

 

 下面分类:

(1) f[ i-1 ][ j ] -> f[ i ][ j ] ,即 ‘<’ 不增加的情况

         可以把数字 i 放到队首或者放在一个 '<' 后面

         一共(j+1)种选择:

         j个 ‘< ’ ,队首一种情况

(2)f[ i-1 ][ j-1 ] -> f[ i ][ j ] ,即 '<' 增加的情况

         可以把数字 i 放在队尾或者一个 '>' 前面

         一共(i-2)-(j-1)+1 -> (i-j)种选择:

         前 i-1 个数字一共 i-2 个符号,其中 j-1 个 '<' ,所以一共(i-2)-(j-1)个 '>' ,队尾一种情况

 

递推式:

 f[ i ][ j ]= max( f[ i ][ j ] , f[ i-1 ][ j ]*( j+1 )+f[ i -1 ][ j-1 ]*( i-j ) )

注意取模,取模一定要多取模,能取模的地方都取模,取模不够会hin尴尬 

 

代码

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>

using namespace std;

inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'||ch>'9') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
    
}

const int mod=2015;
int n,k;
int f[1010][1010];
//f[i][j] 表示前i个数,其中有j个'<',这样的方案数(也就是答案) 

int main()
{
    
    n=read();k=read();
    
    for(int i=1;i<=n;i++) f[i][0]=1;
    //填i个数,一个小于号也没有的排列当然是只有降序排列一种了 
    
    for(int i=1;i<=n;i++) 
      for(int j=1;j<=k;j++)
       f[i][j]=max(f[i][j],(f[i-1][j]%mod*(j+1)%mod+f[i-1][j-1]%mod*(i-j))%mod)%mod;
    //递推式 
    
    printf("%d\n",f[n][k]);
    
    return 0;
}


 

 

 

------我感jio我要多做题多思考QWQ-------

posted @ 2019-07-11 08:07  晔子  阅读(169)  评论(0编辑  收藏  举报