刷题总结——生日礼物(bzoj1293单调队列)

题目:

Description

小西有一条很长的彩带,彩带上挂着各式各样的彩珠。已知彩珠有N个,分为K种。简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置)。某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上。 小布生日快到了,于是小西打算剪一段彩带送给小布。为了让礼物彩带足够漂亮,小西希望这一段彩带中能包含所有种类的彩珠。同时,为了方便,小西希望这段彩带尽可能短,你能帮助小西计算这个最短的长度么?彩带的长度即为彩带开始位置到结束位置的位置差。

Input

第一行包含两个整数N, K,分别表示彩珠的总数以及种类数。接下来K行,每行第一个数为Ti,表示第i种彩珠的数目。接下来按升序给出Ti个非负整数,为这Ti个彩珠分别出现的位置。

Output

应包含一行,为最短彩带长度。

Sample Input

6 3

1 5

2 1 7

3 1 3 8

Sample Output

3

HINT

有多种方案可选,其中比较短的是1~5和5~8。后者长度为3最短。
【数据规模】
对于50%的数据, N≤10000;
对于80%的数据, N≤800000;
对于100%的数据,1≤N≤1000000,1≤K≤60,0≤彩珠位置<2^31。

题解:

先开始读错题了卡了半天23333

一道单调队列的简单题···注意边界条件就行···先将珠子按照位置排序,维护一个单调队列就好了,过程类似于莫队时的维护答案····注意下边界条件就好了

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=1e6+5;
const int M=105;
struct node
{
  int p,c;
}b[N];
int n,m,k,queue[N],head,tail,tot,cnt[M],now,ans=0x7f7f7f7f;
inline int R()
{
  char c;int f=0;
  for(c=getchar();c<‘0‘||c>‘9‘;c=getchar());
  for(;c<=‘9‘&&c>=‘0‘;c=getchar())
    f=(f<<3)+(f<<1)+c-‘0‘;
  return f;
}
inline bool cmp(node a,node b)
{
  return a.p<b.p;
}
int main()
{
  freopen("a.in","r",stdin);
  n=R(),m=R();
  for(int i=1;i<=m;i++)
  {
    k=R();
    for(int j=1;j<=k;j++)
      b[++tot].p=R(),b[tot].c=i;
  }
  sort(b+1,b+tot+1,cmp);
  head=tail=1;cnt[b[1].c]++,now=1;
  for(;head<=tot;head++)
  {
    while(now<m&&tail<=tot)
    {
      tail++;
      if(!cnt[b[tail].c])  now++;
      cnt[b[tail].c]++;
    }
    if(tail==tot+1)  break;
    if(now==m)  ans=min(ans,b[tail].p-b[head].p);
    cnt[b[head].c]--;
    if(!cnt[b[head].c])  now--;
  }
  cout<<ans<<endl;
  return 0;
}
时间: 2025-01-12 18:07:48

刷题总结——生日礼物(bzoj1293单调队列)的相关文章

bzoj 1293: [SCOI2009]生日礼物【单调队列】

一开始用了复杂度看起来对实则常数巨大的线段树+hash--后来发现队列就行-- 把珠子按位置排序,然后用队列维护一段,枚举右端点更新答案即可 #include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int N=1000005,inf=2147483647; int n,m,s[65],ans=inf,tot,sum,l=1,r; struct qwe { int

codevs3327选择数字(单调队列优化)

3327 选择数字 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 给定一行n个非负整数a[1]..a[n].现在你可以选择其中若干个数,但不能有超过k个连续的数字被选择.你的任务是使得选出的数字的和最大. 输入描述 Input Description 第一行两个整数n,k 以下n行,每行一个整数表示a[i]. 输出描述 Output Description 输出一个值表示答案. 样例输入 Sample Input 5 2

HUD 3706 单调队列简单题

Problem Description Give you three integers n, A and B. Then we define Si = Ai mod B and Ti = Min{ Sk | i-A <= k <= i, k >= 1} Your task is to calculate the product of Ti (1 <= i <= n) mod B. 不描述题意了,三行英文挺明了的,今天刚学单调队列,自己模拟一下过了这题 单调队列 1,永远保持队

HDU 4193 Non-negative Partial Sums(想法题,单调队列)

HDU 4193 题意:给n个数字组成的序列(n <= 10^6),求该序列的循环同构序列中,有多少个序列的任意前i项和均大于或等于0. 思路: 这题看到数据规模觉得只能用最多O(nlogn)的算法,然后想到了之前刚做过的有关最小表示法的题,但还没证明出一个做这题有效的算法出来. 后来看过题解,发现用的最多的方法是单调队列,然而我对这个知识点知之甚少orz /*科普君:from单调队列 单调队列是指:队列中元素之间的关系具有单调性,而且,队首和队尾都可以进行出队操作,只有队尾可以进行入队操作.

斜率优化第一题! HDU3507 | 单调队列优化DP

放一手原题 题解: 第一次写(抄)斜率优化,心里还是有点小激动的.讲一下怎么实现的! 首先我们可以考虑一个朴素的dp:DP[i]表示前i个数字的最少花费,显然我们有一个转移方程 DP[i]=min{DP[j]+M+(sum[i]-sum[j])^2} 但是N^2肯定会超时,我们考虑优化他 假设有k<j<i,如果令j对i的贡献比k好 显然我们有这样的式子 DP[j]+M+(sum[i]-sum[j])^2 < DP[k]+M+(sum[i]-sum[j])^2 把平方打开之后移项 可以得到

Sliding Window POJ - 2823 单调队列模板题

Sliding Window POJ - 2823 单调队列模板题 题意 给出一个数列 并且给出一个数m 问每个连续的m中的最小\最大值是多少,并输出 思路 使用单调队列来写,拿最小值来举例 要求区间最小值 就是维护一个单调递增的序列 对于样例 8 3 1 3 -1 -3 5 3 6 7 我们先模拟一遍 1.队列为空 1 进队 队列:1 2.3>队尾元素 3 进队 队列: 1 3 3.-1小于队尾元素,一直从尾部出队知道找到比-1小的元素或者队列为空 队列:-1 当队列中元素大于m的时候从队头删

leecode刷题(26)-- 用栈实现队列

leecode刷题(26)-- 用栈实现队列 用栈实现队列 使用栈实现队列的下列操作: push(x) -- 将一个元素放入队列的尾部. pop() -- 从队列首部移除元素. peek() -- 返回队列首部的元素. empty() -- 返回队列是否为空. 示例: MyQueue queue = new MyQueue(); queue.push(1); queue.push(2); queue.peek(); // 返回 1 queue.pop(); // 返回 1 queue.empty

暑期训练狂刷系列——Foj 1894 志愿者选拔 (单调队列)

题目连接: http://acm.fzu.edu.cn/problem.php?pid=1894 解题思路: 因为出队和入队都满足队列的性质,优先单调队列的优先级有进入队列的顺序和人品的高低,在一段区间中如果出现x[i]是最大的,那么[0,i-1]区间内的数就不用记录了,所以单调队列里面可以按照人品值降序排列,输出的时候判断一下当前元素是否已经出队即可. 1 #include <cstdio> 2 #include <cstring> 3 using namespace std;

hdu 3530 单调队列水题

给你一个数列找到最长的子序列   中的最大值减最小值值m   k之间 建立两个单调队列   一个递增    一个递减    当两个队首满足情况是就进行比较 找到最大值 当不满足是旧的移动队首      怎样移??? 移动队首id较小的一个 #include<stdio.h> #include<string.h> #include<iostream> using namespace std; int max(int a,int b) { return a>b?a:b