Problem Statement
You are given an integer, N and a string, S of the length N−1 consisting of the letters 'G' and 'L'.
A permutation P of the integers from 0 to (N−1) satisfies the pattern denoted by S if the following statements are true for each i from 0 to N−2 :
- If S[i] equals to 'G' then P[i] is greater than P[i+1] .
- If S[i] equals to 'L' then P[i] is less than P[i+1] .
Calculate the number of permutations of the length N that satisfy the given pattern S . Since this number can be large, output it modulo the given integer M .
Input Format
The first line contains two space-separated integers: N and M .
The second line contains a string S of the length N−1 consisting of the uppercase English letters 'L' or 'G'.
Constraints
2≤N≤3000
1≤M≤109
S
consists only of the symbols from the set
{
'L', 'G'
}
.
Output Format
Output the number of permutations modulo M .
Sample Input
3 100
GG
Sample Output
1
Explanation
The only permutation that satisfies the given pattern is (2,1,0) .
题目大意:
给出数组中相邻间的大小关系,求有多少种排列满足给出的要求。
解题思路:
由数据范围知应该是n^2算法,就想到了DP,dp[i][j],i表示第i位,j表示有多少个比当前这个数小。如果i位比i+1位大,下一步有可能dp[i+1][j]就可以从所有的dp[i][k>j]的,同理第i位比i+1小的也一样,于是可以用2个前缀和处理一下。
代码:
#include<iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=3000+10;
int dp[maxn][maxn];
char s[maxn];
int a[maxn];
int b[maxn];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
memset(dp,0,sizeof(dp));
scanf("%s",s);
int ans=0;
for(int i=0;i<n;i++)
dp[1][i]=1;
for(int i=1;i<n;i++)
{
memset(a,0,sizeof(a));
a[0]=dp[i][0];
for(int j=1;j<n;j++)
a[j]=(a[j-1]+dp[i][j])%m;
b[n-1]=dp[i][n-1];
for(int j=n-2;j>=0;j--)
b[j]=(dp[i][j]+b[j+1])%m;
for(int j=0;j<n;j++)
{
if(s[i-1]=='G')
{
if(b[j+1])
dp[i+1][j]=(dp[i+1][j]+b[j+1])%m;
}
else
{
if(i+1+j<=n)
dp[i+1][j]=(dp[i+1][j]+a[j])%m;
}
}
}
cout<<dp[n][0]<<endl;
}
return 0;
}