选数问题【NOIP2016提高A组模拟9.21】

题目

在麦克雷的面前有N个数,以及一个R*C的矩阵。现在他的任务是从N个数中取出R*C个,并填入这个矩阵中。矩阵每一行的法值为本行最大值与最小值的差,而整个矩阵的法值为每一行的法值的最大值。现在,麦克雷想知道矩阵的最小法值是多少。

样例输入:
输入共两行。
第一行是三个整数:n,r,c。
第二行是 n 个整数 Pi。
7 2 3
170 205 225 190 260 225 160

样例输出:
共 m 行,每行一个整数,表示满足条件的对数。
30

数据范围:
30%:1<=n,r,c<=100
50%:1<=n,r,c<=1000
100%:1<=r,c<=10^4,r* c<=n<=5*10^5,0

剖解题目

。。。。。。。。


思路

一般求最优值就是dp之类的,所以很自然就往dp方向去想。
然而设出一个二维的dp状态,发现空间和时间都炸了。
想了一会儿发现空间可以用滚动代替,而时间好像用单调队列可以搞一搞。。。。
搞完后发现时间也炸了。
这道题就炸了。


解法

30%:暴力。
50%:应该是个dp加个优化之类的,就如我当时想的。
100%:二分答案,这样可以省去一维的dp,让时间达到要求。
很明显肯定是按大小顺序选是最优的,先排个序。
二分答案后,判断一下当前的答案下,选进的数是否能够达到r*c个,然后缩小区间。
可以把每c个数的差预处理出来扔进一个数组里,从这个数组里面找只需要找是否有r个就行了。(当然注意这个数组里是不能连续取数的)。


代码

#include
#include
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)

using namespace std;

const int maxn=1e5*5+5;
int b[maxn],a[maxn],f[maxn],n,r,c;

int main()
{
    //freopen("T.in","r",stdin);
    scanf("%d%d%d",&n,&r,&c);
    fo(i,1,n) scanf("%d",&b[i]);
    sort(b+1,b+n+1);
    fo(i,c,n) a[++a[0]]=b[i]-b[i-c+1];
    int l=1,rr=b[n];
    while (lint mid=(l+rr)/2;
        int now=0;
        int i=1,tot=0;
        while (i<=a[0]){
            if (a[i]<=mid) {
                ++tot;
                i+=c;
            }
            else ++i;
        }
        if (tot>=r) rr=mid; else l=mid+1;
    } 
    printf("%d",rr);
}

选数问题【NOIP2016提高A组模拟9.21】_第1张图片

你可能感兴趣的:(信息技术,动态规划,矩阵,分治)