1293: [SCOI2009]生日礼物
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2526 Solved: 1376
[ Submit][ Status][ Discuss]
Description
Input
Output
Sample Input
1 5
2 1 7
3 1 3 8
Sample Output
HINT
有多种方案可选,其中比较短的是1~5和5~8。后者长度为3最短。
【数据规模】
对于50%的数据, N≤10000;
对于80%的数据, N≤800000;
对于100%的数据,1≤N≤1000000,1≤K≤60,0≤彩珠位置<2^31。
Source
开两个数组分别标记当前采用该种类的位置和该种类最后一次出现的位置。首先找到第一个合法区间,然后让这个区间右移,每次右移时找寻当前包含所有种类的区间里最左边的点,因为上一次已经计算过该区间,故令指针指向该种类的下一个出现的位置,直到某一种类到达它最后一次出现的位置为止,停止右移,类似于尺取,因为每个点只会遍历一次,复杂度~=O(n)。
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<math.h>
#include<time.h>
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
typedef long long ll;
#define inf 2147483647
#define mod 1000000007
#define maxn 5000005
#define lowbit(x) (x&-x)
#define eps 1e-10
int flag[100],a[maxn],l[maxn],r[maxn];
int main(void)
{
int n,k,i,j,p;
scanf("%d%d",&n,&k);
for(i=1;i<=k;i++)
{
scanf("%d",&r[i]);
l[i]=a[0]+1;
for(j=1;j<=r[i];j++)
scanf("%d",&a[++a[0]]);
r[i]=a[0];
}
int mins=inf,maxs=-inf;
for(i=1;i<=k;i++)
mins=min(mins,a[l[i]]),maxs=max(maxs,a[l[i]]);
int ans=maxs-mins;
while(1)
{
mins=inf;
for(i=1;i<=k;i++)
{
if(a[l[i]]<mins)
mins=a[l[i]],p=i;
}
if(l[p]!=r[p])
{
l[p]++;
mins=inf;maxs=-inf;
for(i=1;i<=k;i++)
{
if(a[l[i]]<mins)
mins=a[l[i]];
if(a[l[i]]>maxs)
maxs=a[l[i]];
}
ans=min(ans,maxs-mins);
}
else
{
printf("%d\n",ans);
return 0;
}
}
return 0;
}