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