P11456 [USACO24DEC] Interstellar Intervals G 题解
dp 优化题,很好的一道题,有紫的难度。
很容易有一个 \(O(n^2)\) 的时间复杂度,可得到 15pts。
但是这转移很抽象了,明显不能用一般的优化。
由于这个区间肯定是偶数的,所以想到这个转移大概和奇偶有关,枚举到奇数和偶数完全不同,奇数和偶数也不相干。
想到可以分析红蓝对答案的限制来求出答案。
对于(第一个)红色,令它的坐标为 \(la\) ,此时的坐标为 \(i\),那我们就可以确定左端点就是一个确定的区间 \([la*2-i,i]\) ,下界是这个点在分割点的时候取到。
对于蓝色,这个区间求起来很麻烦,因为这个第一个蓝色没有太大的关系,既然我们求区间比较麻烦,那我们就可以对这个蓝色所影响的右端点进行操作。因为蓝色只能在后半区,要保证每一个点(\(x\))只能在 \(2*i-x\) 之前才能对答案由贡献。可以用一个临时变量来维护,类似双指针?
总体的代码可以用树状数组来写,代码不难:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+5,mod=1e9+7;
int n,dp[N],pre1[N],pre2[N];
void toadd(int &x,int y){
x+=y;
if(x>=mod)x-=mod;
if(x<0)x+=mod;
}
struct BIT{
int c[N];
#define lowbit(x) (x&-x)
void add(int x,int w){
while(x<=n+1){
toadd(c[x],w);
x+=lowbit(x);
}
}
int query(int x){
int res=0;
while(x){
toadd(res,c[x]);
x-=lowbit(x);
}
return res;
}
int query(int l,int r){
if(l>r)return 0;
return query(r)-query(l-1);
}
}bit[2];
char s[N];
vector<int>e[N];
signed main(){
scanf("%lld",&n);
scanf("%s",s+1);
dp[0]=1;
bit[0].add(1,dp[0]);
int lb=0,la=0;
for(int i=1;i<=n;i++){
if(s[i]=='X')dp[i]=dp[i-1];
else if(s[i]=='R')la=i;
else {
while(lb<i){
if(i+i-lb<=n)e[i+i-lb].push_back(lb);
lb++;
}
}
for(int c:e[i])bit[c&1].add(c+1,-dp[c]);
int l= max((la-i+la),0ll);
toadd(dp[i],bit[i&1].query(l+1,i+1));
bit[i&1].add(i+1,dp[i]);
}
cout<<dp[n]<<endl;
return 0;
}

浙公网安备 33010602011771号