小a的子序列

小a的子序列

【题目描述】
小a有一个长度为n的序列,但是他忘了这个序列的样子,他只记得序列中的数大小在[1,V]内,你可以任意选择一些位置,并给它们赋值来组成一段子序列,需要满足序列中的数严格递增,一段子序列的“萌值”定义为序列中除最大数外所有数的乘积,若只有1个数则为1。

他想请你求出所有合法子序列的“萌值”的和

不同子序列的定义为:存在某个值不同 或 在原序列中的位置不同

输出答案对10^9+7取模

【输入描述】
两个数n,V

【输出描述】
一个整数表示答案

【样例】
示例1

输入
2 2
输出
5
说明
若X表示不选该位置,那么合法的方案有
1 X = 1
X 1 = 1
1 2 = 1
X 2 = 1
2 X = 1

示例2

输入
3 4
输出
55

【解题思路】:

        dp[i][j]:截止到第i个位置,最大数为j 的答案

      假设有dp1[i][j]:截止到第i个位置,最大数为j 的排列情况数

      则dp1[i][j]=dp1[i-1][j] (当第i个位置不放数时) 情况1

      dp1[i][j]=dp1[i-1][j-1]+dp1[i-1][j-2]+...+dp1[i-1][1];(当第i个位置放数时) 情况2

      dp[i][j] = 情况1+情况2=dp1[i-1][j]+dp1[i-1][j-1]+dp1[i-1][j-2]+...+dp1[i-1][1];

      若是单纯的这样求需要一个循环求第二种情况

      我们可以用一个sum直接累加,就不需要这个循环了

AC_Code:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <string>
 4 #include <cstring>
 5 #include <string>
 6 #include <cmath>
 7 #include <cstdlib>
 8 #include <algorithm>
 9 using namespace std;
10 typedef long long ll;
11 const int maxn = 5010;
12 const ll mod=1e9+7;
13 
14 ll dp[maxn][maxn];
15 int main()
16 {
17     int n,v;
18     while( ~scanf("%d %d",&n,&v)){
19         for(int i=1;i<=v;i++) dp[1][i]=1;
20         for(int i=2;i<=n;i++){
21             int sum=1;
22             for(int j=1;j<=v;j++){
23                 dp[i][j] = (dp[i-1][j]+sum)%mod;
24                 sum = (sum+1ll*dp[i-1][j]*j)%mod;///给下一个dp[i][j]用的,此时的dp[i-1][j]相对于下一个来说是dp[i-1][j-1],
25                                                 ///因为dp[i-1][j]是不算j的,当下一轮时dp[i-1][j+1]是要算j的所以要乘上j
26             }
27         }
28         ll ans=0;
29         for(int i=1;i<=v;i++) ans=(ans+dp[n][i])%mod;
30         printf("%lld
",ans%mod);
31     }
32     return 0;
33 }
原文地址:https://www.cnblogs.com/wsy107316/p/12245646.html