bzoj1293【SCOI2009】生日礼物

想了很久都没有想到。。。看了hzw的题解恍然大悟

居然只是枚举起始位置,然后要取这个位置之前(之后)与它最近的k种珠子的位置的最大值作为这一个起始位置的答案,最后这些答案取min

找最近的珠子:因为题目中已知Ti的珠子位置按升序排序,所以用静态链表把每一种珠子存起来,这样是尾插法,遍历的时候从大到小。同时为了方便,也需要将所有坐标排序,和遍历的顺序一样从大到小枚举起始位置,这样找之前最近比较方便。

get新技能:如果链表中遍历过的东西不要了,可以直接移动头指针,同时能记录位置,和bfs中一样。。。。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
int n,k,x,y,cnt;
typedef int arr[1000010];
arr num,next,a;
int head[100];
int ans;
bool cal(int x)
{
    int tmp=0;
    for (int i=1;i<=k;i++)
    {
        while (num[head[i]]>x)
        {
            if (next[head[i]]==0) return 0;//不能再找了
            head[i]=next[head[i]];//删掉队尾元素,因为已经有序,去掉的可以不要,这样还可以少设变量保存上一次到哪,或者从头再来!!
        }
        if (num[head[i]]<=x) tmp=max(tmp,x-num[head[i]]);
    }
    ans=min(ans,tmp);
    return 1;
}
int main()
{
    cin>>n>>k;
    for (int i=1;i<=k;i++)
    {
        cin>>x;
        for (int j=1;j<=x;j++)
        {
            cin>>y;
            num[++cnt]=y;
            next[cnt]=head[i];
            head[i]=cnt;
            a[cnt]=y;
        }
    }
    sort(a+1,a+cnt+1);
    ans=0x7fffffff;
    for (int i=cnt;i>0;i--)//从后向前找
    {
        if (a[i]!=a[i+1])
            if (!cal(a[i])) break;//有bool值的同时调用
    }
    cout<<ans;
    return 0;
}


你可能感兴趣的:(单调队列)