题解:P11456 [USACO24DEC] Interstellar Intervals G
题目比较关键的点在于存在两种不同的点,因此而存在两种约束条件,对我们问题处理影响非常大。
这类计数题目使用动态规划的概率很大,那么先考虑动态规划。
我们设状态
那么此时的时间复杂度是
首先最显而易见的是区间长度一定是偶数,因此我们可能需要按照奇偶进行分类处理。
我们拆开红色的影响和蓝色的影响进行判断。
假设我们现在需要处理出
假设上一个红色的位置为
那么我们就需要将
但是我们还有蓝色的情况仍然存在影响,需要继续判断。
蓝色的并不像红色的可以直接判断,因为你选择覆盖的红色区间左右端点都在移动,所以这些可以选择进行转移的位置并不是一个区间。
那么我们反过来考虑,处理出每一个点可以被转移到的位置,做一个类似差分的修改操作,然后通过数据结构按照位置维护,通过修改值的大小满足蓝色的条件,通过查询的范围得到维护红色的条件,并且开两组数据结构分别维护即可。
那么我们很明显可以使用树状数组进行维护。
那么继续推出每个值在哪个范围内进行转移即可,只需要考虑下一个蓝色不会包含在红色内即可。
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int n,la,lb,dp[500005];
char s[500005];
vector<int> e[500005];
struct BT{
int c[500005];
int lowbit(int x){
return x&-x;
}
void add(int x,int y){
x++;
for(int i=x;i<=n+1;i+=lowbit(i))c[i]=(c[i]+y+mod)%mod;
}
int query(int x){
x++;
int ans=0;
for(int i=x;i;i-=lowbit(i))ans=(ans+c[i])%mod;
return ans;
}
int query(int l,int r){
if(l>r)return 0;
if(!l)return query(r);
return (query(r)-query(l-1)+mod)%mod;
}
}bit[2];
signed main(){
cin>>n>>s+1;
dp[0]=1;
bit[0].add(0,dp[0]);
for(int i=1;i<=n;i++){
if(s[i]=='X')dp[i]=dp[i-1];
if(s[i]=='R')la=i;
if(s[i]=='B'){
while(lb<i){
if(i+(i-lb)<=n)e[i+(i-lb)].push_back(lb);
lb++;
}
}
for(int v:e[i])bit[v&1].add(v,-dp[v]);
int l=max(la-(i-la),0ll);
dp[i]=(dp[i]+bit[i&1].query(l,i-1))%mod;
bit[i&1].add(i,dp[i]);
}
cout<<dp[n];
return 0;
}