BZOJ 1293 [SCOI2009] 生日礼物 题解与分析

1293: [SCOI2009]生日礼物

Time Limit: 10 Sec   Memory Limit:162 MB
Submit: 630   Solved: 326  
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。

【分析】:
          这道题用贪心的思想。贪心的方法为:对于每种颜色的彩珠,从编号小的地方往后推进,用数组where[x]记录x颜色的珠子已经推进到了哪个地方。首先,在所有颜色当前推进位置中,选出位置编号的最大值max1和最小值min1,很容易想到当前符合题意的长度就是max1-min1<如图一>,这一步是计算。
BZOJ 1293 [SCOI2009] 生日礼物 题解与分析_第1张图片
          然后尝试将某个满足下面条件的颜色的where向后推一位:这一颜色的当前推进位置是所有颜色中最小的,且它的后面那一位最小,这一步是转移<如图二>。
          现在来计算循环次数:有N个珠子,K种颜色,转移需转移N-K次,计算需计算N-K+1次<多的“1”是在初始位置时需要进行一次计算>,因此循环次数为N-K+1。这道题贪心之处就在于每次转移最小值,这样保证情况最优且考虑全面。
【时间复杂度分析】:
          循环次数*(转移+计算):O((N-K+1)*2*K)=O(N*K)
【评测信息】:
          Time:4172 ms ,Memory:9192 kb
【代码】:
/************************************************************** 
    Problem: 1293 
    Language: C++ 
    Result: Accepted 
    Time:4172 ms 
    Memory:9192 kb 
****************************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define MAX 61
#define IMAX 2147483647
struct BALL{vector<int> w;};
BALL a[MAX];
int N,K,first[MAX],ans=IMAX,min1=IMAX,max1=0;
int where[MAX];
int num[MAX];
int main()
{
      //freopen("input.in","r",stdin);
	  //freopen("output.out","w",stdout); 
	  scanf("%d%d",&N,&K);
      for(int i=1;i<=K;i++)
      {
            int A;
            scanf("%d",&A);
			num[i]=A;
            for(int j=1;j<=A;j++)
            {
                  int B;
                  scanf("%d",&B);
                  a[i].w.push_back(B);
            }
			where[i]=0;
      }
      
	  for(int i=1;i<=N-K+1;i++)
	  {
	        int use=1;
	        min1=IMAX,max1=0;
	        for(int j=1;j<=K;j++)
			{
			      min1=min(min1,a[j].w[where[j]]);
				  max1=max(max1,a[j].w[where[j]]);
		    }
		    ans=min(ans,max1-min1);
		    
		    min1=IMAX;
			for(int j=1;j<=K;j++)
			{
			      if(!(where[j]==num[j]-1) && (a[j].w[where[j]]<min1 || (a[j].w[where[j]]==min1 && a[j].w[where[j]+1]<a[use].w[where[use]+1])))
				  {
				        use=j;
						min1=a[j].w[where[j]];
				  }
			}
			where[use]++;
	  }
      printf("%d\n",ans);
	  //system("pause");
      return 0;
}

转载注明出处: http://blog.csdn.net/u011400953

你可能感兴趣的:(BZOJ 1293 [SCOI2009] 生日礼物 题解与分析)