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 ",f[n][k]); return 0; }
------我感jio我要多做题多思考QWQ-------