参考资料:
[1]:https://blog.csdn.net/weixin_43262291/article/details/90271693
题意:
给你一个包含 n 个数的序列 a,并且 max{ai} ≤ x;
定义一个操作 f(L,R) 将序列 a 中 L ≤ ai ≤ R 的数删除;
问有多少对满足条件的 (L,R) 使得执行完 f(L,R) 操作后的序列非递减;
题解:
[1]博文看了一晚上,终于理解了;
枚举左区间 i,找到符合条件的最小的右区间 ki,f(1,k1),f(2,k2),....,f(x,kx);
如果执行完 f(1,k1) 后序列非递减,那么执行完 f(1,k1+1),f(1,k1+2),....,f(1,x) 后同样会使得序列非递减;
f(i,ki)同理,那么最终答案就是 (x-k1+1)+(x-k2+1)+......+(x-kx+1);
如何高效的求解k1,k2,....,kx呢?
首先看看相关变量解释:
int n,x;///max{a[i]} <= x int a[maxn]; int l[maxn];///l[i]:数字i第一次出现的位置 int r[maxn];///r[i]:数字i最后一次出现的位置 int L[maxn];///L[i]:数字[i,n]最先出现的位置 int R[maxn];///R[i]:数字[1,i]最后出现的位置
预处理出l,r,L,R数组:
1 mem(l,INF); 2 mem(r,0); 3 for(int i=1;i <= n;++i) 4 { 5 l[a[i]]=min(i,l[a[i]]); 6 r[a[i]]=i; 7 } 8 mem(L,INF); 9 mem(R,0); 10 for(int i=x;i >= 1;--i) 11 L[i]=min(L[i+1],l[i]); 12 for(int i=1;i <= x;++i) 13 R[i]=max(R[i-1],r[i]);
明确一点,k1 ≤ k2 ≤ ...... ≤ kx;
那么,首先求出 k1,然后,递推出 ki;
如何求解k1呢?
上述查找可转化为找最小的 k1 使得 [k1+1,x] 组成的序列非递减;
int k=x;///如果[k,x]非递减,那么k-1找下一个位置 for(;k > 1 && r[k] <= L[k+1];--k);
如何根据 k1 递推出 ki 呢?
for(int i=2;i <= x && R[i-2] <= l[i-1];++i) for(;k < i || R[i-1] > L[k+1];++k);///找到第一个使得R[i-1]>=L[k+1]的k
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mem(a,b) memset(a,b,sizeof(a)) 4 #define ll long long 5 #define INF 0x3f3f3f3f 6 const int maxn=1e6+50; 7 8 int n,x;///max{a[i]} <= x 9 int a[maxn]; 10 int l[maxn];///l[i]:数字i第一次出现的位置 11 int r[maxn];///r[i]:数字i最后一次出现的位置 12 int L[maxn];///L[i]:数字[i,n]最先出现的位置 13 int R[maxn];///R[i]:数字[1,i]最后出现的位置 14 15 ll Solve() 16 { 17 mem(l,INF); 18 mem(r,0); 19 for(int i=1;i <= n;++i) 20 { 21 l[a[i]]=min(i,l[a[i]]); 22 r[a[i]]=i; 23 } 24 mem(L,INF); 25 mem(R,0); 26 for(int i=x;i >= 1;--i) 27 L[i]=min(L[i+1],l[i]); 28 for(int i=1;i <= x;++i) 29 R[i]=max(R[i-1],r[i]); 30 31 32 int k=x;///如果[k,x]非递减,那么k-1找下一个位置 33 for(;k > 1 && r[k] <= L[k+1];--k); 34 35 ll ans=x-k+1; 36 37 ///要确保[1,i-1]非递减 38 ///且已知[k+1,x]非递减 39 for(int i=2;i <= x && R[i-2] <= l[i-1];++i) 40 { 41 for(;k < i || R[i-1] > L[k+1];++k);///找到第一个使得R[i-1]>=L[k+1]的k 42 43 ans += x-k+1; 44 } 45 return ans; 46 } 47 int main() 48 { 49 // freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin); 50 scanf("%d%d",&n,&x); 51 for(int i=1;i <= n;++i) 52 scanf("%d",a+i); 53 54 printf("%lld\n",Solve()); 55 return 0; 56 }