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

来源:互联网 发布:2s19自行榴弹炮知乎 编辑:程序博客网 时间:2024/05/20 04:13

题目

在麦克雷的面前有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<cstdio>#include<algorithm>#include<cstring>#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 (l<rr){        int 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);}

这里写图片描述

0 0
原创粉丝点击