不妨假设
S
0
=
R
S_0=R
S0=R,做出如下观察:
1.1
1.1
1.1 不存在
B
B
B的连续段
1.2
1.2
1.2 不存在长度为偶数的
R
R
R的连续段
1.3
1.3
1.3 对于
S
i
=
L
S_i=L
Si=L的情况,事实上这个棋子的移动方向是确定的,取决于上一段
R
R
R的奇偶性
1.4
1.4
1.4 设
S
S
S中连续的
R
R
R最短为
Y
Y
Y,如果圆上任意圆弧的长度
≤
Y
\le Y
≤Y,那么可以从圆弧一端走到另一端,因此一定合法。能否证明这是充要的呢?取最长一段圆弧和最短一段
R
R
R,从圆弧的两端出发逆序操作就能找到出发点。因为圆弧两端奇偶性不同,因此必然存在一个点跨过了整段圆弧,证毕。 注意,我们只考虑长度为奇数的连续的
R
R
R。
1.5
1.5
1.5对于
S
S
S中长度为偶数的连续的
R
R
R,发现可以缩掉,这样会出现连续的
B
B
B,那么只要不是出现在开头,这些
B
B
B都没有影响,因此如果开头的
R
R
R是奇数,那么不用考虑,如果是偶数,设长度为
Z
Z
Z,那么圆弧长度不能超过
Z
+
1
Z+1
Z+1,据此对
Y
Y
Y修正即可。
大力 d p dp dp即可。复杂度 O ( n ) O(n) O(n)。
似乎细节比较多
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int mod=1e9+7;
int n,m,a[200005],L(inf);
ll dp[200005][2],f[200005],res;
string s;
ll ask(int i,int j){
return i<=0?0:dp[i][j];
}
signed main(){
cin>>n>>m>>s;for(int i=0;i<m;i++)a[i+1]=(s[i]=='R');
if(!a[1])for(int i=1;i<=m;i++)a[i]^=1;
int j=1;
for(int i=1;i<=m;i++){
if(!a[i]){
if((i-j)&1)L=min(L,i-j);
else if(j==1)L=min(L,i);
j=i+1;
}
}if(L==inf){
f[1]=1;res=n+1;
for(int i=2;i<n;i++){
ll x=f[i-2];
f[i]=(f[i-1]+x)%mod;
res=(res+(n-i+1)*x)%mod;
}cout<<res<<"\n";
return 0;
}
dp[1][1]=1;if(L>=n-1&&(n-1&1))res=n;
for(int i=2;i<n;i++){
ll x=ask(i-1,i&1)-ask(i-L-2,i&1);
dp[i][i&1]=(dp[i-1][i&1]+x)%mod;
dp[i][!(i&1)]=dp[i-1][!(i&1)];
if(n-i<=L&&(n-i&1))res=(res+(n-i+1)*x)%mod;
}
cout<<(res+mod)%mod;
}