Educational Codeforces Round 65 (Rated for Div. 2) E. Range Deleting(思维+coding)

传送门

 

参考资料:

  [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 }
View Code

 

转载于:https://www.cnblogs.com/violet-acmer/p/10908926.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值