B(升降序列)

B(升降序列)

pic


题目

【题目描述】

对于一个排列,考虑相邻的两个元素,如果后面一个比前面一个大,表示这个位置是上升的,用 I 表示,反之这个位置是下降的,用 D 表示。如排列 3,1,2,7,4,6,5 可以表示为 DIIDID。

现在给出一个长度为 n-1 的排列表示,问有多少种 1 到 n 的排列满足这种表示。

【输入输出格式】

输入格式:
一个字符串 S,S 由 I,D,?组成。?表示这个位置既可以为 I,又可以为 D。

输出格式:
有多少种排列满足上述字符串。输出排列数模 1000000007。

【输入输出样例】

输入样例#1:
?D
输出样例#1:
3
【说明】
对于 20%的数据,S 长度 ≤ 10;
对于 100%的数据,S 长度 ≤ 1000。

思路

dp。
\(dp[i][j]\)表示i这么长的序列,最后一个是j的符合要求的序列个数
于是有方程:

\[ dp_{i,j}= \begin{cases} \sum_{k=1}^{j-1} dp_{i-1,k} \ \ \text{Order='I'} \\[1ex] \\ \sum_{k=j}^{i-1} dp_{i-1,k}\ \ \text{Order='D'}\end{cases} \]

为了简化计算,计算\(dp_{i,...}\)之前,把\(dp_{i-1,...}\)处理成前缀和的形式。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define mod 1000000007
#define LL long long
#define File freopen("B.in","r",stdin);freopen("B.out","w",stdout)
using namespace std;
const int maxn=1000+5;

LL n=1,dp[maxn][maxn],ans;
char c;

int main() {
    ios::sync_with_stdio(false);
//    File;
    c=getchar();
    dp[1][1]=1;
    while(c=='?' || c=='D' || c=='I') {
        n++;
        for(LL i=1; i<n; ++i) {
            dp[n-1][i]=(dp[n-1][i]+dp[n-1][i-1])%mod;
        }
        if(c=='I') {
            for(LL i=2; i<=n; ++i)
                dp[n][i]=dp[n-1][i-1]%mod;
        }
        if(c=='D') {
            for(LL i=1; i<n; ++i) {
                dp[n][i]=(dp[n-1][n-1]-dp[n-1][i-1]+mod)%mod;
            }
        }
        if(c=='?') {
            for(LL i=2; i<=n; ++i) {
                dp[n][i]=dp[n-1][i-1]%mod;
            }
            for(LL i=1; i<n; ++i) {
                dp[n][i]+=(dp[n-1][n-1]-dp[n-1][i-1]+mod)%mod;
            }
        }
        c=getchar();
    }
    ans=0;
    for(LL i=1; i<=n; ++i) {
        ans+=dp[n][i];
        ans=ans%mod;
    }
    cout<<ans%mod;
    return 0;
}

转载于:https://www.cnblogs.com/YQAccelerator/p/7413783.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值