题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4055
和前一题类似。
DP方程为:
dp[i][j] 表示长度为i以j结尾的合法的排列个数(由1...i组成的排列)。
还要清楚一个结论:
给定一个长度为i-1的字符串,由{1,2,...,i}组成的合法排列数和由{1,2,...,j-1,j+1,...,i+1}
组成的合法排列数是相同的。
if ( s[i] == 'I' ) dp[i][j] = dp[i-1][1] + dp[i-1][2] + ... + dp[i-1][j-1];
if ( s[i] == 'D' ) dp[i][j] = dp[i-1][j] + dp[i-1][j+1] +...+ dp[i-1][i-1];
if ( s[i] == '?' ) dp[i][j] = dp[i-1][1] + dp[i-1][2] + ... + dp[i-1][i-1];
O(n^3)的解法:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;
#define Maxn 1005
#define MOD 1000000007
#define LL long long
LL dp[Maxn][Maxn];
LL ans[Maxn];
char str[Maxn];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
int len;
while(scanf(" %s",str)!=EOF)
{
len = strlen(str);
memset(dp,0,sizeof(dp));
memset(ans,0,sizeof(ans));
dp[1][1] = 1;
ans[1] = 1;
for(int i=0;i<len;i++)
{
int temp = i + 2;
if(str[i] == 'I' || str[i] == '?')
{
for(int j=1;j<=temp;j++)
{
for(int k=1;k<=j-1;k++)
{
dp[temp][j] = (dp[temp][j] + dp[temp - 1][k])%MOD;
}
ans[temp] = (ans[temp] + dp[temp][j])%MOD;
}
}
if(str[i] == 'D' || str[i] == '?')
{
ans[temp] = 0;
for(int j=1;j<=temp;j++)
{
for(int k=j;k<=temp-1;k++)
{
dp[temp][j] = (dp[temp][j] + dp[temp - 1][k])%MOD;
}
ans[temp] = (ans[temp] + dp[temp][j])%MOD;
}
}
}
printf("%lld\n",ans[len+1]);
}
return 0;
}
可以用sum维护一个前缀和,这样复杂度降为O(n^2),如果还超时的话,注意在mod处优化一下,可以变成减号。
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;
#define Maxn 1005
#define MOD 1000000007
#define LL __int64
LL dp[Maxn][Maxn];
LL sum[Maxn][Maxn];
char str[Maxn];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
int len;
while(scanf(" %s",str)!=EOF)
{
len = strlen(str);
memset(dp,0,sizeof(dp));
memset(sum,0,sizeof(sum));
dp[1][1] = 1;
sum[1][1] = 1;
for(int i=0; i<len; i++)
{
int temp = i + 2;
for(int j=1; j<=temp; j++)
{
if(str[i] == 'I')
{
dp[temp][j] = sum[temp-1][j-1];
}
else if(str[i] == 'D')
{
dp[temp][j] = sum[temp-1][temp-1] - sum[temp-1][j-1];
if(dp[temp][j] < 0) dp[temp][j] += MOD;
}
else
{
dp[temp][j] = sum[temp-1][temp-1];
}
sum[temp][j] = sum[temp][j-1] + dp[temp][j];
if(sum[temp][j] > MOD) sum[temp][j] -= MOD;
}
}
printf("%I64d\n",sum[len+1][len+1]);
}
return 0;
}