Wannafly Winter Camp 2019 Day4 G 置置置换 (oeis/DP)

版权声明:欢迎神犇指教 https://blog.csdn.net/sdxtcqs/article/details/86617177

https://zhixincode.com/contest/16/problem/G?problem_id=243
题意:求 1.. n 1..n 的排列中满足对于任意 i > 1 i>1 ,若 i i 为奇数 a i 1 < a i a_{i-1}<a_i ,若 i i 为偶数 a i 1 > a i a_{i-1}>a_i n < = 1000 n<=1000

这题比赛的时候暴力出了前10项就oeis了,然后查到一篇关于齿排列的论文https://max.book118.com/html/2015/0907/24832737.shtm直接找到了递推公式如下 A 0 = A 1 = 1 A_0=A_1=1 2 A n + 1 = k = 0 n ( n k ) A k A n k   ( n 1 ) 2A_{n+1}=\sum^{n}_{k=0}\dbinom{n}{k}A_kA_{n-k}\ (n\ge1)
然后就直接写上去交了,要注意除以 2 2 的时候要用乘法逆元,因为这个WA了一发。

讲题的时候才知道正解应该是DP,DP想起来也不是很难,令 f [ i ] [ j ] f[i][j] 表示前 i i 个数以 j j 结尾的符合题目条件的 1.. i 1..i 的排列。
i i 是奇数时(山峰),要求前面的数比 j j 小,可得 f [ i ] [ j ] = k = 1 j 1 f [ i 1 ] [ k ] f[i][j]=\sum^{j-1}_{k=1}{f[i-1][k]}
i i 是偶数时(山谷),要求前面的数比 j j 大,然而之前并没有出现 i i 这个数字,但是有一个巧妙的方法就是可以将之前出现过的大于等于 j j 的数字全部加 1 1 ,即可符合条件,所以可得 f [ i ] [ j ] = k = j i 1 f [ i 1 ] [ k ] f[i][j]=\sum^{i-1}_{k=j}{f[i-1][k]}
这显然是个 O ( n 3 ) O(n^3) 的做法,使用前缀和可以优化到O(n^2)。

//直接套用齿排列递推公式
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int MOD=1000000007;
int n;
long long A[1010];
long long C[1010][1010];
int main()
{
    scanf("%d",&n);
    A[0]=A[1]=A[2]=1;
    C[1][0]=C[1][1]=1;
	for (int i=2;i<=1000;i++)
	{
		C[i][0]=1;
		for(int j=1;j<=1000;j++)
        {
            C[i][j]=(C[i-1][j]+C[i-1][j-1]);
            C[i][j]%=MOD;
        }
	}
    for(int i=3;i<=1000;i++)
    {
        for(int j=0;j<=i-1;j++)
        {
            A[i]+=(C[i-1][j]*A[j]%MOD)*A[i-1-j] % MOD;
            A[i]%=MOD;
        }
        A[i]=(A[i] * 500000004)%MOD;
    }
    printf("%lld\n",A[n]);
    return 0;
}
//DP做法
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
const int MOD=1000000007;
int f[1010][1010],s[1010][1010];
int main()
{
    int n;
    scanf("%d",&n);
    f[1][1]=s[1][1]=1;
    for(int i=2;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
        {
            if(i%2==1)
            {
                f[i][j]=s[i-1][j-1]%MOD;
                s[i][j]=(s[i][j-1]+f[i][j])%MOD;
            }
            if(i%2==0)
            {
                f[i][j]=(s[i-1][i-1]-s[i-1][j-1]+MOD)%MOD;
                s[i][j]=(s[i][j-1]+f[i][j])%MOD;
            }
        }
    }
    printf("%d\n",s[n][n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sdxtcqs/article/details/86617177
今日推荐