整天做一些模板题感觉药丸
设(val_i)表示第(i)个位置的值
看到区间最大值考虑最值分治。对于当前的区间([l,r]),找到区间最大值(mid),递归([l,mid-1])和([mid+1,r]),然后考虑pair((i,j)(i in [l,mid] , r in [mid,r]))的贡献。
扫([l,mid])和([mid,r])中较短的一段区间,那么对于扫到的一个位置(i),它的贡献就是另一段区间中值小于等于(lfloor frac{val_{mid}}{val_i} floor)的位置的数量,使用主席树维护即可。
#include<bits/stdc++.h>
//this code is written by Itst
using namespace std;
int read(){
int a = 0; char c = getchar();
while(!isdigit(c)) c = getchar();
while(isdigit(c)){
a = a * 10 + c - 48;
c = getchar();
}
return a;
}
#define ll long long
#define lb lower_bound
#define ub upper_bound
const int _ = 1e5 + 7;
namespace segTree{
int lch[_ * 20] , rch[_ * 20] , sum[_ * 20] , cntN;
#define mid ((l + r) >> 1)
int modify(int x , int l , int r , int tar){
int t = ++cntN;
sum[t] = sum[x] + 1; lch[t] = lch[x]; rch[t] = rch[x];
if(l == r) return t;
if(mid >= tar) lch[t] = modify(lch[t] , l , mid , tar);
else rch[t] = modify(rch[t] , mid + 1 , r , tar);
return t;
}
int query(int x , int l , int r , int R){
if(r <= R) return sum[x];
int sum = query(lch[x] , l , mid , R);
if(mid < R) sum += query(rch[x] , mid + 1 , r , R);
return sum;
}
}
int rt[_] , val[_] , lsh[_] , ST[21][_] , logg2[_] , N , cntL;
int cmp(int a , int b){return val[a] > val[b] ? a : b;}
void init(){
logg2[0] = -1;
for(int i = 1 ; i <= N ; ++i){
ST[0][i] = i;
logg2[i] = logg2[i >> 1] + 1;
}
for(int i = 1 ; 1 << i <= N ; ++i)
for(int j = 1 ; j + (1 << i) - 1 <= N ; ++j)
ST[i][j] = cmp(ST[i - 1][j] , ST[i - 1][j + (1 << (i - 1))]);
}
int qST(int l , int r){
int t = logg2[r - l + 1];
return cmp(ST[t][l] , ST[t][r - (1 << t) + 1]);
}
ll solve(int l , int r){
if(l > r) return 0;
if(l == r) return lsh[val[l]] == 1 ? 1 : 0;
int Mid = qST(l , r) , w = lsh[val[Mid]];
ll sum = solve(l , Mid - 1) + solve(Mid + 1 , r);
int L = l , R = Mid , rgeL = Mid , rgeR = r;
if(Mid - l > r - Mid){
swap(rgeL , L); swap(rgeR , R);
}
while(L <= R){
int num = ub(lsh + 1 , lsh + cntL , w / lsh[val[L]]) - lsh - 1;
if(num)
sum += segTree::query(rt[rgeR] , 1 , cntL , num) - segTree::query(rt[rgeL - 1] , 1 , cntL , num);
++L;
}
return sum;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
//freopen("out","w",stdout);
#endif
N = read();
for(int i = 1 ; i <= N ; ++i)
val[i] = lsh[i] = read();
sort(lsh + 1 , lsh + N + 1);
cntL = unique(lsh + 1 , lsh + N + 1) - lsh;
for(int i = 1 ; i <= N ; ++i){
val[i] = lb(lsh + 1 , lsh + cntL , val[i]) - lsh;
rt[i] = segTree::modify(rt[i - 1] , 1 , cntL , val[i]);
}
init();
cout << solve(1 , N);
return 0;
}