常州模拟赛d5t2 mogician

分析:一个暴力的思想是枚举g,然后枚举每个数ai,看能不能符合要求,这样复杂度是O(nA)的,直接T掉了.也没什么其他的办法了,在暴力的基础上优化一下,优化的关键是要如何快速统计出不满足要求的数的个数.利用数据结构?想不到.仔细分析一下,不满足要求的数组成了很多区间,每次i枚举g的倍数,不满足要求的数的区间总在[i + k + 1,i + g - 1]中,因为i+k+1通过减k满足不了要求,i+g-1比g的倍数少了1,那么利用前缀和数组维护一下个数就好了.不过有一种特殊情况:k >= g - 1,这样无论如何都是满足要求的,因此在前缀和的时候要判断一下左右端点是否合理.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

const int maxn = 3000010;

int sum[maxn], num[maxn],t,n,k,f,mx;

int main()
{
    scanf("%d", &t);
    while (t--)
    {
        memset(sum, 0, sizeof(sum));
        memset(num, 0, sizeof(num));
        scanf("%d%d%d", &n, &k, &f);
        for (int i = 1; i <= n; i++)
        {
            int t;
            scanf("%d", &t);
            num[t]++;
            mx = max(mx, t);
        }
        for (int i = 1; i <= mx; i++)
            sum[i] = sum[i - 1] + num[i];
        for (int g = 1; g <= mx; g++)
        {
            int cnt = sum[g - 1];
            for (int i = g; i + k + 1 <= mx && cnt <= f; i += g)
            {
                int l = i + k + 1, r = min(mx, i + g - 1);
                if (l <= r)
                cnt += sum[r] - sum[l - 1];
            }
            if (cnt <= f)
                printf("%d ", g);
        }
        printf("\n");
    }

    return 0;
}

 

posted @ 2017-08-26 09:22  zbtrs  阅读(266)  评论(0编辑  收藏  举报