生日礼物(我的思维崩盘题- -.)

个人心得:做完这题发现自己有多水,先是思路崩盘,后面借鉴思路之后再试,编程崩盘。好吧,全程崩盘,我要很无奈。

总的来说,还是自己思维的不严谨性和不会更好的模拟和运用学过的知识,还是有待进步!

好吧先看这道令我奔溃的题吧,可能是我太水了!!!

小西有一条很长的彩带,彩带上挂着各式各样的彩珠。已知彩珠有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<如图一>,这一步是计算。
          然后尝试将某个满足下面条件的颜色的where向后推一位:这一颜色的当前推进位置是所有颜色中最小的,且它的后面那一位最小,这一步是转移<如图二>。
          现在来计算循环次数:有N个珠子,K种颜色,转移需转移N-K次,计算需计算N-K+1次<多的“1”是在初始位置时需要进行一次计算>,因此循环次数为N-K+1。这道题贪心之处就在于每次转移最小值,这样保证情况最优且考虑全面。
【时间复杂度分析】:
          循环次数*(转移+计算):O((N-K+1)*2*K)=O(N*K)
个人心得:挺不错的思想,可是实施起来比较麻烦,每次选最小的,后面看到其他的大神用了优先队列发现挺完美,不过终止条件和结构体的建立要思考,结构体必须包括他所属的颜色和在的位置,答案的代码是直接建立最大数据的结构体数组,一个颜色标志,一个存储位置,还有个就是存储下一个同等颜色的位置,
我发现BZOJ的水题都比较高档昂。这道题的基本思想是,每次用优先队列把位置最靠前的颜色弹出来,并把与它颜色相同的下一个点的位置进队列,每次更新最优长度。

    1.初始化:每个点的下一个相同颜色点的位置。

    2.将每个颜色的第一个点入队列,算第一个状态。

    3.每次将队列最前端的颜色弹出,将他的下一个点放入队列,更新最优长度。

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<utility>
 6 #include<queue>
 7 #define MAXN 1000010
 8 #define INF (1<<30)
 9 using namespace std;
10 int t[61],s[61];
11 struct node{
12     int first;
13     int second;
14     int next;
15     node(){};
16     void init(int x,int y,int z){
17         first=x;
18         second=y;
19         next=z;
20     }
21     friend bool operator < (node a,node b){
22         return a.second>b.second;
23     }
24 }x[MAXN];
25 priority_queue<node> q;
26 int main(){
27     s[0]=0;
28     int n,k,l,r=0;
29     scanf("%d%d",&n,&k);
30     for(int i=1;i<=k;i++){
31         scanf("%d",&s[i]);
32         s[i]=s[i]+s[i-1];
33         for(int j=s[i-1]+1;j<=s[i];j++) {
34             int a;
35             scanf("%d",&a);
36             x[j].init(i,a,j+1);
37         }
38     }
39     for(int i=0;i<k;i++) {
40         r=max(r,x[s[i]+1].second);
41         q.push(x[s[i]+1]);
42     }
43     int ans=r-q.top().second;
44     while(1){
45         node tmp=q.top();
46         q.pop();
47         if(tmp.next-1<s[tmp.first]) {
48             r=max(x[tmp.next].second,r);
49             q.push(x[tmp.next]);
50         }
51         else break;
52         tmp=q.top();
53         ans=min(r-tmp.second,ans);
54     }
55     printf("%d",ans);
56     return 0;
57 }
原文地址:https://www.cnblogs.com/blvt/p/7263997.html