版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhlbjtu2016/article/details/82597486
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4055
题意:给了一组字符串包含'?','I','D'。'I'代表当前字符比后一个字符大,'D'代表当前字符比后一个字符小,'?'则都可以。询问有多少个这样的排列(包含1-n+1,n为字符串的长度)
分析:递推。有两种情况
第一种是第i个为I(小于号,升序):dp[i][j] = dp[i-1][j-1] + dp[i-1][j-2] + .. + dp[i-1][1]
另一种是第i个为D(大于号,降序): dp[i][j] = dp[i-1][i] + dp[i-1][i-1] + ... + dp[i-1][j]
注意第二种情况如果当前位为j,前面出现过j,则前面所有的数都要加上1,也满足条件,其余细节看代码注释
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1010;
const int mod = 1000000007;
typedef long long ll;
char s[maxn];
ll sum[maxn][maxn];
int main()
{
while(~scanf("%s",s))
{
int len = strlen(s);
memset(sum,0,sizeof(sum));
sum[0][1] = 1;//0个符合有数字为1的情况只有1种
for(int i = 1; i <= len; i++)//对于len个符号有len+1个数字组成
{
if(s[i - 1] == 'I')//第i个符号为'I',代表第i个数字到第i+1个数字是递增的
{
for(int j = 1; j <= i + 1; j++)//i个符号,有i+1个数字,最后一个数字为j的所有情况由之前的递推得到
{
sum[i][j] = sum[i][j - 1];//i个符号,最后一个数字为j-1的情况之前算过,最后一个数字为j的情况包含最后一个数字为j-1的情况
sum[i][j] = (sum[i - 1][j - 1] + sum[i][j]) % mod;//i-1个符号,最后一个数字是j-1的情况也算过,最后一个数字为j的话一定满足递增
}
}
else if(s[i - 1] == 'D')//第i个符号为'D',代表第i个数字到第i+1个数字是递减的
{
for(int j = i + 1; j > 0; j--)//i个符号,有i+1个数字,最后一个数字为j的所有情况由之前的递推得到
{
sum[i][j] = sum[i][j + 1];//i个符号,最后一个数字为j+1的情况之前算过,最后一个数字为j的情况包含最后一个数字为j+1的情况
sum[i][j] = (sum[i - 1][j] + sum[i][j]) % mod;//i-1个符号,最后一个数字是j+1的情况也算过,最后一个数字为j的话一定满足递减
}
}
else//第i个符号是'?',则第i个数字啥都可以
{
ll tmp = 0;
for(int j = 1; j <= i; j++)
tmp += sum[i - 1][j] % mod;
for(int j = 1; j <= i + 1; j++)//i个符号,i+1个数字,最后一个数字无论是什么都加上i-1个符号的所有情况
sum[i][j] = tmp;
}
}
ll ans = 0;
for(int i = 1; i <= len + 1; i++)//长度为len+1最后一位是1-len+1的所有情况
ans += sum[len][i] % mod;
cout<<ans % mod<<endl;
}
return 0;
}