题意:给定一个字符串,I表示本字符要比前一个字符大,D表示本字符要不前一个字符小,?可大可小,问1~n的所有排列中,有多少满足条件
/* dp方程的设定比较显然,dp[i][j]表示选了i个元素,最后一个是j的方案数。 但是在状态转移的时候,我们不得不考虑前面选了什么,也就是状态的设定是有后效性的, 所以考虑给状态再添一层含义:必须选前i个元素。 那么这样岂不是每次只能选i吗?那么第二维岂不是没有用了? 所以我们考虑用j把i替换出来,那么在状态转移的时候就需要考虑放入i时,怎么替换能使原来的大小顺序保持不变。 将dp[i-1][j]的i-1个数的序列中 ≥j 的数都加1,这样i-1变成了i,j变成了j+1,而j自然就补在后面了。 处理I:dp[i][j] = Σdp[i-1][x],其中1≤x≤j-1,可进一步简化,dp[i][j] = dp[i][j-1]+dp[i-1][j-1] 处理D:dp[i][j] = Σdp[i-1][x],其中j≤x≤i-1,可进一步简化,dp[i][j] = dp[i-1][j+1]+dp[i-1][j] 处理?:dp[i][j] = Σdp[i-1][x],其中1≤x≤i-1 */ #include<iostream> #include<cstdio> #include<cstring> #define N 1010 #define mod 1000000007 using namespace std; int dp[N][N],n; char s[N]; int main(){ while(scanf("%s",s+1)!=EOF){ memset(dp,0,sizeof(dp)); n=strlen(s+1);n++; dp[1][1]=1; for(int i=2;i<=n;i++){ if(s[i-1]=='I'){ for(int j=2;j<=i;j++) dp[i][j]=(dp[i][j-1]+dp[i-1][j-1])%mod; } else if(s[i-1]=='D'){ for(int j=i-1;j>=1;j--) dp[i][j]=(dp[i][j+1]+dp[i-1][j])%mod; } else { int sum=0; for(int j=1;j<i;j++) sum+=dp[i-1][j],sum%=mod; for(int j=1;j<=i;j++) dp[i][j]=sum; } } int ans=0; for(int i=1;i<=n;i++) ans+=dp[n][i],ans%=mod; printf("%d ",ans); } return 0; }