BZOJ1293 [SCOI2009]生日礼物 离散化
欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - BZOJ1293
题意概括
彩珠有N个,分为K种。每一个彩珠有一个对应的坐标。坐标上可以没有彩珠,多个彩珠也可以出现在同一个位置上。小西希望一段彩带中能包含所有种类的彩珠。帮助小西计算这段彩带这个最短的长度。彩带的长度即为彩带开始位置到结束位置的位置差。
题解
水题。
对于读入的,先离散化一下。
然后L和R卡过去就可以了。直接看代码应该就懂了吧?
如果不懂,建议去做做NOIP2016普及组T3。
代码
#include <cstring> #include <algorithm> #include <cstdio> #include <cmath> #include <cstdlib> #include <vector> using namespace std; const int N=1000000+5,M=60+5; int n,m,Hash[N],hs,tot[M]; vector <int> a[M],tre[N]; void Get_Hash(){ sort(Hash+1,Hash+hs+1); int hs_=1; for (int i=2;i<=hs;i++) if (Hash[i]!=Hash[i-1]) Hash[++hs_]=Hash[i]; hs=hs_; } int find(int x){ int le=1,ri=hs,mid; while (le<=ri){ mid=(le+ri)>>1; if (Hash[mid]==x) return mid; if (Hash[mid]<x) le=mid+1; else ri=mid-1; } return -1; } int main(){ scanf("%d%d",&n,&m); hs=0; for (int i=1,t,x;i<=m;i++){ scanf("%d",&t); a[i].clear(); while (t--){ scanf("%d",&x); a[i].push_back(x); Hash[++hs]=x; } } Get_Hash(); for (int i=1;i<=hs;i++) tre[i].clear(); for (int i=1;i<=m;i++) for (int j=0;j<a[i].size();j++) tre[find(a[i][j])].push_back(i); memset(tot,0,sizeof tot); int ans=2147483647,L=0,R=0,cnt=0; while (R<hs){ R++; for (int i=0;i<tre[R].size();i++){ if (!tot[tre[R][i]]) cnt++; tot[tre[R][i]]++; } while (cnt==m&&L<R){ L++; ans=min(ans,Hash[R]-Hash[L]); for (int i=0;i<tre[L].size();i++){ tot[tre[L][i]]--; if (!tot[tre[L][i]]) cnt--; } } } printf("%d",ans); return 0; }