题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6701
题目大意为求满足 $max(a_{l},a_{l+1}\cdot \cdot \cdot a_{r})-(r-l+1)<=k$的区间个数。
先预处理出前缀最大值和后缀最大值和ST表,然后分治。
每次可以得到这次分治区间的区间最大值,然后我们要求出以该最大值为区间最大值时的合法区间数目。
这里我们可以枚举合法区间的左端点(右端点),然后通过化简上式得到合法的右端点(左端点),选择枚举左还是右端点由当前区间最大值的位置所决定,因为左端点一定在最大值左边,右端点一定在最大值右边,所以选择数量较小的一边来枚举。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<set> 6 using namespace std; 7 typedef long long ll; 8 typedef unsigned long long ull; 9 const int maxn = 3e5 + 110; 10 int a[maxn], pos[maxn], L[maxn], R[maxn], Log[maxn]; 11 int n, k; 12 int dp[maxn][20]; 13 int query(int l, int r) { 14 int k = Log[r - l + 1]; 15 if (a[dp[l][k]] > a[dp[r - (1 << k) + 1][k]]) 16 return dp[l][k]; 17 else 18 return dp[r - (1 << k) + 1][k]; 19 } 20 ll dfs(int l, int r) { 21 if (l == r)return a[l] - 1 <= k; 22 if (l > r)return 0; 23 int cnt = query(l, r); 24 ll ans = 0; 25 if (cnt - l < r - cnt) { 26 for (int i = l; i <= cnt; i++) { 27 int ls = max(cnt, i + a[cnt] - k - 1); 28 int rs = min(r, R[i]); 29 if (rs >= ls) 30 ans += rs - ls + 1; 31 } 32 } 33 else { 34 for (int i = cnt; i <= r; i++) { 35 int ls = max(l, L[i]); 36 int rs = min(i - (a[cnt] - k) + 1, cnt); 37 if (rs >= ls) ans += rs - ls + 1; 38 } 39 } 40 return ans + dfs(l, cnt - 1) + dfs(cnt + 1, r); 41 } 42 int main() { 43 int t; 44 scanf("%d", &t); 45 while (t--) { 46 scanf("%d%d", &n, &k); 47 for (int i = 1; i <= n; i++) 48 scanf("%d", &a[i]); 49 Log[0] = -1; 50 for (int i = 1; i <= n; i++) Log[i] = Log[i >> 1] + 1; 51 for (int i = 1; i <= n; i++) 52 dp[i][0] = i; 53 for (int j = 1; (1 << j) <= n; j++) { 54 for (int i = 1; i + (1 << j) - 1 <= n; i++) { 55 if (a[dp[i][j - 1]] > a[dp[i + (1 << (j - 1))][j - 1]]) 56 dp[i][j] = dp[i][j - 1]; 57 else 58 dp[i][j] = dp[i + (1 << (j - 1))][j - 1]; 59 } 60 } 61 for (int i = 0; i <= n; i++)pos[i] = 0; 62 R[n + 1] = n; 63 for (int i = n; i >= 1; i--) { 64 if (pos[a[i]]) { 65 R[i] = pos[a[i]] - 1; 66 pos[a[i]] = i; 67 } 68 else { 69 pos[a[i]] = i; 70 R[i] = n; 71 } 72 R[i] = min(R[i], R[i + 1]); 73 } 74 for (int i = 0; i <= n; i++)pos[i] = 0; 75 for (int i = 1; i <= n; i++) { 76 if (pos[a[i]]) { 77 L[i] = pos[a[i]] + 1; 78 pos[a[i]] = i; 79 } 80 else { 81 pos[a[i]] = i; 82 L[i] = 1; 83 } 84 L[i] = max(L[i], L[i - 1]); 85 } 86 printf("%lld\n", dfs(1, n)); 87 } 88 }