C1672 [Wannafly冬令营2018Day4]置置置换(dp)

在这里插入图片描述
思路:
定义f (i, j)为长度为i,结尾数字为j的方案数
i 为奇数的时候,a[i] > a[i - 1], f (i, j) 的子状态为∑f(i - 1,k) (1 ≤ k ≤ j - 1)。
i 为偶数的时候,a[i] < a[i - 1], f (i, j) 的子状态为∑f(i - 1,k) (j ≤ k ≤ i - 1)。
注意到,i为偶数的时候f(i, j) 可以从 f(i - 1,j)转移过来,有点难理解。i - 1长度串末尾已经是j了,你怎么再添一个j进去??

很明显,这个串是一个锯齿形的结构。一上一下一上一下。
那么当a[i] < a[i - 1]的时候,你把前面大于j的数字都+1,对于这个结构没有影响。
假设 a[k - 1] < a[k] > a[k + 1],那么假设a[k + 1](a[k - 1]) > a[i]的话,那么a[k]也会同时加一,没有影响。假设只有a[k] > a[j]的话,只有a[k]++,也没有影响。

a[k - 1] > a[k] < a[k + 1]的时候,也是一样的思路。
所以 i 为偶数的时候f(i, j)的子状态可以是 f(i - 1,j)。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long ll;
const int mod = 1e9 + 7;
ll f[1005][1005];
int main()
{
    int n;scanf("%d",&n);
    
    for(int i = 1;i <= n;i++)
        f[1][i] = 1;
    
    for(int i = 2;i <= n;i++)
    {
        if(i % 2)
        {
            f[i][1] = 0;
            for(int j = 2;j <= i;j++)
                f[i][j] = (f[i][j - 1] + f[i - 1][j - 1]) % mod;
        }
        else
        {
            f[i][i] = 0;
            for(int j = i - 1;j >= 1;j--)
                f[i][j] = (f[i][j + 1] + f[i - 1][j]) % mod;
        }
    }
    ll ans = 0;
    for(int i = 1;i <= n;i++)
        ans = (ans + f[n][i]) % mod;
    printf("%lld\n",ans);
    return 0;
}

发布了594 篇原创文章 · 获赞 16 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/103588397
今日推荐