【问题描述】

czy有很多妹子,妹子虽然数量很多,但是质量不容乐观,她们的美丽值全部为负数(喜闻乐见)。

czy每天都要带N个妹子到机房,她们都有一个独一无二的美丽值,美丽值为-1到-N之间的整数。他想要把这些妹子排成一个波动序列,这样相对“漂亮”(美丽值的绝对值较小)的妹子可以与她旁边的两个美丽值的绝对值较大的妹子形成鲜明的对比,整个序列相对将更加“美观”(不再那么无法直视)。

一个序列是波动序列仅当序列中的每个数比周围的两个数都大或都小(如果有的话)。

现在czy希望知道,长度为N的波动序列有多少种。两种序列A和B不同当且仅当存在一个i,使得Ai≠Bi。由于这个数目可能很大,你只对它除以P的余数感兴趣。

【输入格式】

输入文件czy.in仅含一行,两个正整数N, P。

【输出格式】

输出文件czy.out仅含一行,一个非负整数,表示你所求的答案对P取余之后的结果。

【样例输入输出】

czy.in

4 7

czy.out

3

说明:共有10种可能的序列,它们是:  1324 1423 2143 2314 2413  3142 3241 3412 4132 4231

(忽略负号)

【数据规模和约定】

对于20%的数据,满足N≤10;

对于40%的数据,满足N≤18;

对于70%的数据,满足N≤550;

对于100%的数据,满足3≤N≤4200,P≤10^9。

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);
}
05-11 14:42