cf 1257 E. The Contest(好题)(LIS/思维)

Posted initrain

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cf 1257 E. The Contest(好题)(LIS/思维)相关的知识,希望对你有一定的参考价值。

题意:

有三个序列,a、b、c,每次操作可以把一个序列中的一个数移动到另一个序列中,

问,最少操作几次后,可以使得 a 序列里的所有数 小于 b 里面的所有数,b 里面的小于 c 里面的。

数字不重复,总共2e5的数据量。

 

思路:

做法一:(LIS)

这个做法是网上看到的,确实挺巧妙的,用这个方法,即使以后来个100个序列的,也不用怕了。

分别对a b c 排序,然后合并,

求最大上升子序列,然后上升子序列里的数不动,只移动非序列里的,答案就是 n - len,len最大,答案就最小。

求LIS的时候,要用树状数组优化一下,这样复杂度才能是 O(n*logn )。

 

做法二:(乱搞)

这个是自己瞎想想出来的,复杂度O(n),不过只适用于三个序列的。

三个序列里的,看做三种颜色记作颜色c1、c2、c3,然后混在一起排序,

然后每次固定一个左端点 l,表示移动到最后 1~l 为序列a里的数,查找一个可以使操作最小的右端点 r ,表示到最后 l+1~r 为序列b里的数,那么剩下的 r+1~n 就是序列c里的数。

怎么找操作最小的右端点r呢,先假设l不存在,也就是我们现在只把序列分为两段,

当右端点为 i 时,显然,操作数就是 1~i 的c3的数量 加上 i+1~n的 c2的数量,(这个就是需要对序列b c操作的次数)(对a操作的次数很好求,就是不在1~l 里的c1的数量)

为什么可以假设 l 不存在,因为当 l 移动的时候,如果吞掉一个c3,那么,r 在 l + 1 ~ n 每个点时的操作数就是全部减一,所以最小值的位置不变,只是值减一而已。

只分两段的时候,我们就很容易求 r 在 j ~ n时的最小值,这个就从后往前更新一下就好了。

 

所以,简而言之,就是预处理 j~n 的 r 的最小的位置在哪里,然后枚举 l ,更新答案。

(每次思维题我思路都讲得乱七八糟的。。。)

 

代码:

做法一:(LIS)

技术图片
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <queue>
#include <functional>
using namespace std;
const int maxn = 2e5 + 10;
const int inf = 0x3f3f3f3f;
int dp[maxn],mx[maxn];
int lowbit(int i){
    return i & (-i);
}
void insert(int i,int x,int n){
    while(i <= n){
        mx[i] = max(mx[i],x);
        i += lowbit(i);
    }
}
int _find(int i){
    int res = 0;
    while(i > 0){
        res = max(mx[i],res);
        i -= lowbit(i);
    }
    return res;
}

int LIS(int a[],int n){
    int res = 0;
    memset(mx,0,sizeof(mx));
    memset(dp,0,sizeof(dp));
    for(int i = 1;i <= n;i++){
        dp[a[i]] = _find(a[i]) + 1;
        res = max(res,dp[a[i]]);
        insert(a[i],dp[a[i]],n);
    }
    return res;
}
int a[maxn],b[maxn];
int main(){
    int _n[3],n;
    while(scanf("%d%d%d",&_n[0],&_n[1],&_n[2]) != EOF){
        n = 0;
        int cnt = 0;
        for(int k = 0;k < 3;k++){
            for(int i = 1;i <= _n[k];i++)
                scanf("%d",&b[i]);
            sort(b + 1,b + _n[k] + 1);
            for(int i = 1;i <= _n[k];i++)
                a[++cnt] = b[i];
            n += _n[k];
        }
        
        int ans = LIS(a,n);
        printf("%d
",n - ans);
    }
    return 0;
}
View Code

 

做法二:(乱搞)

技术图片
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
int sum2[maxn],sum3[maxn],mi_p[maxn],mi[maxn];
int vis[maxn];
int main(){
    int n1,n2,n3,x,n;
    while(scanf("%d%d%d",&n1,&n2,&n3) != EOF){
        memset(vis,0,sizeof(vis));
        n = n1 + n2 + n3;
        for(int i = 1;i <= n1;i++){
            scanf("%d",&x);
            vis[x] = 1;
        }
        for(int i = 1;i <= n2;i++){
            scanf("%d",&x);
            vis[x] = 2;
        }
        for(int i = 1;i <= n3;i++){
            scanf("%d",&x);
            vis[x] = 3;
        }

        sum3[0] = 0;
        for(int i = 1;i <= n;i++){
            sum3[i] = sum3[i - 1];
            if(vis[i] == 3)
                sum3[i]++;
        }
        sum2[n + 1] = 0;
        for(int i = n;i >= 1;i--){
            sum2[i] = sum2[i + 1];
            if(vis[i] == 2)
                sum2[i]++;
        }

        int mival = sum3[n],ans = 1e9;
        mi[n] = sum3[n];
        for(int i = n - 1;i >= 1;i--){
            mi[i] = mi[i + 1];
            if(mival > sum3[i] + sum2[i + 1]){
                mival = sum3[i] + sum2[i + 1];
                mi[i] = mival;
            }
        }
        mi[0] = min(sum2[1],mi[1]);
        
        int one = 0,sub = 0,res;
        ans = n2 + n3;
        for(int i = 0;i < n;i++){
            if(vis[i] == 1)
                one++;
            if(vis[i] == 3)
                sub++;
            res = (i - one) + mi[i] - sub + (n1 - one);
            if(res < ans)
                ans = res;
        }
        printf("%d
",ans);
    }
    return 0;
}
View Code

 

以上是关于cf 1257 E. The Contest(好题)(LIS/思维)的主要内容,如果未能解决你的问题,请参考以下文章

CF1257EThe Contest线段树

Codeforces 1257E - The Contest

CF思维E. Replace the Numbers

CF 1117 E. Decypher the String

Educational Codeforces Round 76 (Rated for Div. 2) E. The Contest

cf 1305 E. Kuroni and the Score Distribution