【P2401】不等数列(DP)
这个题乍一看就应该是DP,再看一眼数据范围,1000.。那就应该是了。然后就向DP的方向想,经过对小数据的计算可以得出,如果我们用f[i][j]来表示前i个数有j个是填了"<"的,那么f[i][j]显然可以表示为f[i][j]+=f[i-1][j]\*(j+1)+f[i-1][j-1] (i-j).
至于原因
1.与f[i-1][j-1]
在这种情况下,由于我们是从前往后去推的,所以当前加入的数一定比前面的都大。那么怎么才能使得其变为前n个有j个<呢?
仔细想一下你就会发现,你把这个数插入任何一个数后面,都必将“形成”一个小于号,但是如果我们插入到一个已经形成小于号的两数之间,则小于号数量就不会改变,因为前i-1个数都比当前的i小,所以一共有i-1个空位,但是又有j-1个空位已经形成<号,所以在这种情况下,前i个数形成的每一个有j-1个<的数列都可以形成(i-1)-(j-1)个新的前i个数中有j个<的数列,于是从f[i-1][j-1]能够推出f[i][j]的一部分为f[i-1][j-1]*((i-1)-(j-1))。
2.与f[i-1][j]
那么刚刚是说明了你加入这个数增加了一个小于号的情况。但如果我不增加呢?
我前i-1个数已经形成了j个<。那么我加入i使其不会增加小于号要怎么做呢?
由于上文我已经说过你把这样的i插入两个之间已经是<号的数之间是不会增加<的数量的。所以这样的空位,每一个形成前i-1数有j个<的数列就有j个这样的空位。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #define re register #define ll long long #define mo 2015 using namespace std; int n,k,l,f[1001][1001],ans; int main() { cin>>n>>k; for(re int i=1;i<=n;i++) { f[i][i-1]=1; f[i][0]=1; } for(re int i=1;i<=n;i++) { for(re int j=1;j<i-1;j++) { f[i][j]+=f[i-1][j]*(j+1)+f[i-1][j-1]*(i-j); f[i][j]%=mo; } } cout<<f[n][k]%mo; }
对于作者转载文章,欢迎继续转载。
对于作者原创文章,请注明出处之后转载。