HackerRank Week of Code -18 GG


Problem Statement

You are given an integer, N and a string, S of the length N1 consisting of the letters 'G' and 'L'.

A permutation P of the integers from 0 to (N1) satisfies the pattern denoted by S if the following statements are true for each i from 0 to N2 :

  • 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 N1 consisting of the uppercase English letters 'L' or 'G'.

Constraints

2N3000
1M109
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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值