一开始我想的递推方向想得很复杂,看了别人的博客后才醍醐灌顶:
参照他的思路和代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int mod = ;
const int N = ; char s[N];
int dp[N][N], sum[N][N]; int main() {
while(~scanf("%s",s + )) {
memset(dp,,sizeof(dp));
// memset(sum,0,sizeof(sum));
dp[][] = sum[][] = ;
int n = strlen(s + );
for(int i = ; s[i]; ++i) {
for(int j = ; j <= i; ++j) {
if(s[i] == 'I' || s[i] == '?')
dp[i][j] = (dp[i][j] + sum[i - ][j - ]) % mod;
if(s[i] == 'D' || s[i] == '?')
dp[i][j] = (dp[i][j] + (sum[i - ][i - ] - sum[i - ][j - ] + mod) % mod) % mod;
sum[i][j] = (sum[i][j - ] + dp[i][j]) % mod;
}
}
printf("%d\n",sum[n + ][n + ]);
}
return ;
}
用类似的思路我独自 A 出了这道题,只是需要对 dp 数组和 sum 数组加多一维记录当前第 i 位是凹点还是凸点:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL; LL dp[][][], sum[][][]; inline void init(int n = ) {
dp[][][] = dp[][][] = ;
sum[][][] = sum[][][] = ;
for(int i = ; i <= n; ++i) {
for(int j = ; j <= i; ++j) {
dp[i][j][] += sum[i - ][j - ][];
dp[i][j][] += (sum[i - ][i - ][] - sum[i - ][j - ][]);
sum[i][j][] = sum[i][j - ][] + dp[i][j][];
sum[i][j][] = sum[i][j - ][] + dp[i][j][];
}
}
} int main() {
int t,num,n;
init();
scanf("%d",&t);
while(t--) {
scanf("%d %d",&num,&n);
printf("%d %I64d\n", num, n == ? : sum[n][n][] + sum[n][n][]);
}
return ;
}
空间是可以优化的,不过对于这样的数据范围没必要。