每个点有向左,向右,都可以,三种跳跃属性。问从起点到终点的,经过每个点一次的方案数。
我们要求的就是合法的全排列,满足起点是第一个,终点是最后一个,任何一个可以到下一个的数量。
我们考虑最后的这个排列,从1开始,对每个数考虑其应该放在哪里。
我们发现,任何时刻,这样放出来的连通块,右端点一定是R或B,左端点一定是L或B。
因为我们从1~n添加,所以没有添加的数一定比添加了的数大。如果是右端点,就要到达一个比自己大的,那我只能向右。
反之就是向左。
然后我们发现,要产生这样的限制,只能说明我跟连通块发生了关系(或者自己成了一个新连通块)
所以可以设置状态f[i][j]表示考虑到数i,现在有j个连通块的方案数。
但是我们发现,起点和终点的位置是确定的,要提出来讨论。所以我们设free为不是起点,终点的连通块数量。
所以状态转移是这样的:
如果i+1是起点:
其要么自成一个新连通块,要么和一个普通连通块连在一起。
如果i+1是终点:
其要么自成一个新连通块,要么和一个前面的普通连在一起。
如果都不是:
1:自成一个连通块
2。和起点连通块连接。
3。和起点连通块以及一个普通连通块连接。
4。和终点连接。
5。和终点连通块以及一个普通连通块连接。
6。成为一个普通块的右端点。
7。成为一个普通块的左端点。
8。连接两个普通联通块。
然后就写吧,,
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
int cnt=0,f=1;char ch=0;
while(!isdigit(ch)){
ch=getchar();if(ch=='-')f=-1;
}
while(isdigit(ch)){
cnt=cnt*10+ch-48;
ch=getchar();
}return cnt*f;
}
const int mod=1e9+7;
int f[5003][5003];
char ch[5003],n,s,e;
signed main(){
scanf("%s",ch+1);
n=strlen(ch+1);s=in;e=in;
f[0][0]=1;
for(int i=0;i<=n-2;i++){
int st;if(i==0)st=0;else st=1;
for(int j=st;j<=i;j++){
long long key=f[i][j];if(!key)continue;
int free=j;
if(i>=s)free--;if(i>=e)free--;if(free<0)continue;char x=ch[i+1];
if(i+1==s){
if(x=='R'||x=='B')f[i+1][j+1]=(f[i+1][j+1]+key)%mod;
if(x=='L'||x=='B')f[i+1][j]=(f[i+1][j]+key*free)%mod;
}
else if(i+1==e){
f[i+1][j+1]=(f[i+1][j+1]+key)%mod;
f[i+1][j]=(f[i+1][j]+key*free)%mod;
}
else{
if(x=='R'||x=='B')f[i+1][j+1]=(f[i+1][j+1]+key)%mod;
if(i+1>s&&(x=='R'||x=='B'))f[i+1][j]=(f[i+1][j]+key)%mod;
if(i+1>s&&(x=='L'||x=='B')&&j)f[i+1][j-1]=(f[i+1][j-1]+key*free)%mod;
if(i+1>e&&(x=='L'||x=='B'))f[i+1][j]=(f[i+1][j]+key)%mod;
if(i+1>e&&(x=='L'||x=='B')&&j)f[i+1][j-1]=(f[i+1][j-1]+key*free)%mod;
if(x=='R'||x=='B')f[i+1][j]=(f[i+1][j]+free*key)%mod;
if(x=='L'||x=='B')f[i+1][j]=(f[i+1][j]+free*key)%mod;
if(free>=2&&(x=='L'||x=='B'))f[i+1][j-1]=(f[i+1][j-1]+key*free%mod*(free-1)%mod)%mod;
}
}
}int ans=0;
if(n==s){if(ch[n]=='L'||ch[n]=='B')ans=f[n-1][1];}
else if(n==e)ans=f[n-1][1];
else if(ch[n]=='L'||ch[n]=='B')ans=f[n-1][2];
cout<<ans;
return 0;
}