链接
http://acm.hdu.edu.cn/showproblem.php?pid=4055
题解
这题代码就这么短!但是不好想
f[i][j]
f
[
i
]
[
j
]
表示
1...i
1...
i
的排列,最后一个数字是
j
j
,能够得到的符合前个符号的序列个数
当符号为
D
D
时,
显然位置要放一个大于
j
j
的,也就是,但是我没有
i
i
啊,这怎么转移?考虑因为在最后一个数字,所以前
i−1
i
−
1
个位置只有
i−1
i
−
1
种数字,它们是
1...j−1,j+1...i
1...
j
−
1
,
j
+
1...
i
,如果我把
j+1...i
j
+
1...
i
都减去
1
1
,这样不就回到了?
所以
当
s[i]=D
s
[
i
]
=
D
时
f[i][j]=∑i−1k=jf[i−1][k]
f
[
i
]
[
j
]
=
∑
k
=
j
i
−
1
f
[
i
−
1
]
[
k
]
当
s[i]=I
s
[
i
]
=
I
时
f[i][j]=∑jk=1−1f[i−1][j−1]
f
[
i
]
[
j
]
=
∑
k
=
1
j
−
1
f
[
i
−
1
]
[
j
−
1
]
当
s[i]=?
s
[
i
]
=
?
时
f[i][j]=∑j−1k=1[k]
f
[
i
]
[
j
]
=
∑
k
=
1
j
−
1
[
k
]
代码
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <cmath>
#define maxn 1010
#define ll_inf (1ll<<60)
#define ll long long
#define cl(x,y) memset(x,y,sizeof(x))
#define mod 1000000007
using namespace std;
int f[maxn][maxn], s[maxn][maxn], N;
char str[maxn];
void dp()
{
int i, j;
cl(f,0), cl(s,0);
s[1][1]=f[1][1]=1;
N=strlen(str+2)+1;
for(i=2;i<=N;i++)for(j=1;j<=i;j++)
{
if(str[i]=='D')f[i][j]=(s[i-1][i-1]-s[i-1][j-1])%mod;
if(str[i]=='I')f[i][j]=s[i-1][j-1];
if(str[i]=='?')f[i][j]=s[i-1][i-1];
s[i][j]=(s[i][j-1]+f[i][j])%mod;
}
printf("%d\n",(s[N][N]+mod)%mod);
}
int main()
{
while(~scanf("%s",str+2))dp();
return 0;
}