Educational Codeforces Round 190 D. Good Schedule
Good Schedule
解题思路
核心观察:
1.区间计数问题,如果存在单调性,可以考虑固定左端点查询最大右端点或固定右端点查询最小左端点,这题显然可以固定左端点数合法右端点数量
2.对于每个区间从区间内 $ {a_i=1} $ 的第一个位置开始,每个位置贪心跳到后一个比当前位置大 \(1\) 的位置。因此可以记录一下后缀数组快速找到比当前大 \(1\) 的最近位置,以及区间内第一个 \(1\) 出现的位置
3.以上做法还是可以卡到 \(n^2\) ,考虑继续优化,发现从区间 端点 \(l\) 跳到的最远位置是确定的,每个点能够跳到最远的位置只进行一次计算后就能反复调用。这可以通过倒序遍历预处理技巧或记忆化搜索技巧做到,算法也可以达到严格 $ O(n) $的复杂度。
AC code
//Stop learning useless algorithms, go and solve some problems, learn how to use binary search.
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
const ll INF=1e17;
void solve(){
int n;cin>>n;
vector<ll>a(n+1);
vector<ll>b(n+1);
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>b[i];
vector<int>lasA(n+1,n+1),lasB(n+1,n+1);
vector<int>las(n+2,n+1);
vector<int>nxt(n+1,n+1);
for(int i=n;i>=1;i--){
lasA[a[i]]=i;
lasB[b[i]]=i;
if(a[i]+1<=n) nxt[i]=min(lasA[a[i]+1],lasB[a[i]+1]);
}
ll ans=0;
vector<int>dp(n+2,-1);
auto dfs=[&](auto &&dfs,int r) ->int {
if(dp[r]!=-1) {
return dp[r];
}
if(r>n||a[r]!=b[r]){
return dp[r]=r;
}
return dp[r]=dfs(dfs,nxt[r]);
};
for(int i=n;i>=1;i--){
las[i]=las[i+1];
if(a[i]==1||b[i]==1) las[i]=i;
bool f=true;
int r=i;
while(true){
if(f) {
r=las[r];
f=false;
}
else {
r=dfs(dfs,r);
break;
}
if(r>n||a[r]!=b[r]) break;
}
ans+=r-i;
}
cout<<ans<<endl;
}
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
int T=1;cin>>T;
while(T--) solve();
return 0;
}

浙公网安备 33010602011771号