持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情
本文已参与「新人创作礼」活动,一 起开启掘金创作之路。
题目
中文翻译
中文大意
就是让我们在数组a种选取一段连续的区间作为数组b数组b的下标从一开始并且问一共有多少种方法
双指针解法
我们会发现如果这段区间的数字符合题意那么这段区间也是一定符合题意的所有我们只需要维护有边界r即可
int a[N];
void solve()
{
int res = 0;
int n; cin >> n;
rep(i,n) cin >> a[i];
int l = 1,r = 1;
int cnt = 1;
for(l; l <= n; l++) {
r = max(l,r);
while(r + 1 <= n && a[r + 1] >= cnt + 1) {
r ++;
cnt ++;
}
cnt--;
cnt = max(1ll,cnt);
// cout << r - l + 1 << endl;
int len = r - l + 1;
res += len;
}
cout << res << endl;
}
线段树写法
我们发现如果以为区间的左端点那么这样我们可以发现符合的区间一定是连续的所以我们可以采用线段树二分来写这题
const int N = 2e5 + 10;
int a[N];
int f[N << 2];
int Max[N << 2], Min[N << 2];
void Built(int k,int l,int r) {
Max[k] = 0ll;
Min[k] = 1e18;
if( l == r) {
f[k] = a[l];
Max[k] = Min[k] = a[l];
return;
}
int m = l + r >> 1;
Built(k << 1,l,m);
Built(k << 1|1,m + 1,r);
Max[k] = max(Max[k << 1],Max[k << 1|1]);
Min[k] = min(Min[k << 1],Min[k << 1|1]);
}
int Binary_search(int k,int l,int r,int x) {
if(r <= x) return r;
if(x < Min[k]) return -1;
if(x >= Max[k]) return r;
int m = l + r >> 1;
int res = Binary_search(k << 1,l,m,x);
if(res == m) {
return max(res,Binary_search(k << 1|1,m + 1,r,x));
}else return res;
}
void solve() {
int n;cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
a[i] = i - a[i] + 1;
}
// rep(i,n) cout << a[i] << " \n"[ i == n];
a[0] = 1e9;
Built(1,1,n);
int ans = 0;
for (int i = 1; i <= n; i++) {
int R = Binary_search(1,1,n,i);
// cout << "----" << R << endl;
ans += R - i + 1;
}
cout << ans << endl;
}