ACM - CF - 1496B - 二分

CF题目链接

题意:
给定一n个数的数组,数组元素不重复,给定k次操作。问:k次操作之后,数组中不重复的元素个数是多少。
操作定义为:(max{} + mex{}) / 2向上取整。
其中:max{}是数组中最大的数,mex{}是数组中第一个未出现的自然数。

样例解释:
4 1
0 1 3 4
1次操作,mex{} = 2, max{} = 4, 添加3,答案是4
3 1
0 1 4

3 0
0 1 4
0次操作,答案是3
3 2
0 1 2
两次操作,mex{}=3, max{}=2, 添加3;mex{}=4,max=3,添加4,答案是5
3 2
1 2 3
两次操作,mex{}=0, max{}=3, 添加2,变成{1 2 2 3};第二次操作,mex{}=0, max{}=3,变成{1 2 2 2 3},答案是3

两个点:
(1)mex{}怎么计算,即找第一个未出现的自然数
数组排序。若a[i] = i,说明在i之前都是有序的,且都出现了。即二分

(2)题目的k次,骗人的。重点是不同的数。
观察后两个样例。
第一个,由于出现了 0 ~ n-1,根据规则,mex{}=n, max{}=n-1, 会添加n;所以第二次添加n+1,以此类推
第二个,由于2是重复出现的,所以之后都不用再算。k那么大,一直算,会超时的
这两个即为边界条件

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 20;
int T,n,k;
int a[maxn];

int main(){
    //freopen("input.txt", "r", stdin);
    scanf("%d",&T);
    while(T--){
        memset(a, 0, sizeof(a));
        scanf("%d%d", &n, &k);
        for(int i = 0; i < n; i++)
            scanf("%d", &a[i]);
        sort(a, a+n);

        if (a[n - 1] == n - 1){
            printf("%d\n", n + k);
            continue;
        }
        int l, r, mid, maxx = a[n - 1], tmp;
        //printf("%d\n", maxx);
        int num;
        for(num = 1; num <= k; num++){
            //printf("num = %d\n", num);
            l = 0;
            r = n - 1 + num - 1;
            while(l <= r){
                mid = (l + r) >> 1;
                //printf("%d %d\n", mid, a[mid]);
                if (a[mid] == mid)
                    l = mid + 1;
                else
                    r = mid - 1;
            }
            //printf("%d\n", l);
            tmp = (l + maxx + 1) / 2;
            //printf("tmp = %d maxx = %d\n", tmp, maxx);

            l = 0;
            r = n - 1 + num - 1;
            while(l <= r){
                mid = (l + r) >> 1;
                if (a[mid] <= tmp)
                    l = mid + 1;
                else
                    r = mid - 1;
            }

            //printf("l,r,mid = %d %d %d %d %d %d\n", l, a[l], r, a[r], mid, a[mid]);

            for(int i = n - 1 + num - 1; i >= l ; i--)
                a[i + 1] = a[i];
            a[l] = tmp;
            if (l > 0 && a[l - 1] == tmp) break;
            if (a[l + 1] == tmp) break;

            //sort(a, a + n + num);
            //for(int i = 0; i < n + num; i++)
            //    printf("%d%c", a[i], i == n + num - 1 ? '\n' : ' ');
        }
        int cnt = 1;
        for(int i = 1; i < n + num; i++)
            if (a[i] != a[i - 1] && a[i])
                cnt++;
        printf("%d\n", cnt);
        //for(int i = 0; i < n + num; i++)
        //    printf("%d%c", a[i], i == n + num - 1 ? '\n' : ' ');
    }
    return 0;
}
全部评论

相关推荐

11-27 17:35
已编辑
蚌埠坦克学院 C++
深信服 后台开发 n×12
点赞 评论 收藏
分享
菜菜咪:1. 可以使用简历网站的模版,美观度会更好一点 2. 邮箱可以重新申请一个,或者用qq邮箱的别名,部分hr可能会不喜欢数字邮箱 3. 项目经历最好分点描述,类似的项目很多,可以参考一下别人怎么写的 4. 自我评价可加可不加,技术岗更看重技术。最后,加油,优秀士兵
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务