小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 }