AHSOFNU高一互测题【czy系列赛】第二题:dp……顺手写了个
要了解更多关于czy系列赛的东西,快戳这里
(我会说其实第四题是我出的吗)
现场没有想出来怎么做,在orz了黄巨大之后才知道
有些猥琐的dp。f[i][j]表示前i个数、第一个数在[1,j]范围内且第一段是下降的方案数(够坑吧)
那么f[i][j] = f[i][j - 1] + f[i - 1][i - j]
什么意思呢?首先开头是[1,j-1]的方案数是已经算过的,可以直接取出来,就是f[i][j - 1]
那么我们考虑开头是j、第一段是下降的方案怎么转移:
黄巨大是这样说的:这个就是求以[1,j]开头的1到 i-1的第一位上升合法排列数
就是说我们把j加到第一个并要使得第一段是下降的,那么j要比原来的第一个要大,并且原来的方案必须是上升(这样才能保证整个序列是波动序列)
根据上升与下降的对称性,我们可以得出f[i-1][i-j]即是所求
那么前面的方程就解释完了
最后答案是2*f[n][n],因为上升下降都得算
顺便说一句,bzoj上会卡f[4201][4201]的内存,所以要用滚动数组,否则MLE别怪我没提醒你
#include<cstdio> int n,k,pre,cur; int f[2][5000]; int main() { scanf("%d%d",&n,&k); if (n==1) { printf("%d\n",1); return 0; } pre=1;cur=0; f[pre][1]=1; for (int i=2;i<=n;i++) { pre^=1;cur^=1; for (int j=1;j<=n;j++) { f[pre][j]=f[pre][j-1]; if (i>=j)f[pre][j]+=f[cur][i-j]; if (f[pre][j]>k) f[pre][j]-=k; } } printf("%d",(f[pre][n]*2)%k); }
——by zhber,转载请注明来源