zoukankan      html  css  js  c++  java
  • bzoj 1293: [SCOI2009]生日礼物 问题转化 + 性质分析 + 滚动数组优化

    Description

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

    题解:

    十分简单,独自想出来的.
    题目中要求最短的一段区间,使得该区间有所有的色块种类.
    考虑枚举右端点,设该区间左端点的色块为 $i$,那么 $i$ 一定是距离右端点最近的一个 $i$ ,即 $i$ 的位置是从右端点开始数起 $i$ 首次出现的位置.
    证明:
    如果不是最近的,那么可以将该区间缩短,因为 $i$ 在距离右端点更近的位置有替代者.
    色块只有 60 个,考虑将坐标离散化暴力转移即可,途中顺便维护距离每一个坐标距离最远且第一次出现的距离,所有点中该值的最小值就是答案.

    直接开数组会炸掉,滚动优化一下即可. 

    Code:

    #include<bits/stdc++.h>
    #define setIO(s) freopen(s".in","r",stdin) 
    #define maxn 1010000 
    #define inf 0x7fffffff 
    using namespace std;
    void Min(int &a,int b) 
    { 
        if(b<a) a=b; 
    }
    void Max(int &a,int b) 
    { 
        if(b>a) a=b; 
    }
    struct Node
    {
        int id,d;   
        Node(int a=0,int b=0):id(id),d(d){} 
    }nodes[maxn]; 
    bool cmp(Node a,Node b)
    {
        return a.d<b.d; 
    }
    int arr[maxn],lst[2][61];    
    int main()
    {
        // setIO("input");   
        int n,k,m,cnt=0; 
        scanf("%d%d",&n,&k);
        for(int i=1;i<=k;++i)
        {
            int t,x; 
            scanf("%d",&t);    
            for(int j=1;j<=t;++j) 
            {
                scanf("%d",&x);
                nodes[++cnt].id=i, nodes[cnt].d=x; 
            }
        } 
        sort(nodes+1,nodes+1+n,cmp);            
        for(int i=1;i<=n;++i) arr[i]=nodes[i].d;   
        for(int j=0;j<=60;++j) lst[0][j]=lst[1][j]=inf; 
        for(int i=1;i<=n;++i) 
        {
            nodes[i].d=lower_bound(arr+1,arr+1+n,nodes[i].d)-arr;   
        }                           
        int ans=inf, cur=0; 
        for(int i=1,j;i<=n;i=j+1) 
        { 
            j=i;
            int posl=nodes[i-1].d;
            int posc=nodes[i].d;
            int rec=0;  
            while(nodes[j+1].d==nodes[i].d) ++j;           
            for(int jj=i;jj<=j;++jj) lst[cur][nodes[jj].id]=0;    
            for(int jj=1;jj<=k;++jj)        
            {
                if(lst[cur^1][jj]!=inf) 
                {
                    Min(lst[cur][jj],lst[cur^1][jj]+arr[posc]-arr[posl]);     
                }
                rec=max(rec,lst[cur][jj]);  
            }     
            for(int j=0;j<=60;++j) lst[cur^1][j]=inf; 
            cur^=1;    
            Min(ans,rec);
              
        }
        printf("%d",ans); 
        return 0; 
    }
    

      

  • 相关阅读:
    821. 字符的最短距离
    1122. 数组的相对排序
    258. 各位相加
    C++常见问题之二#define使用中的陷阱
    python进阶二_基本数据类型与操作
    DirectX10一变换(三)
    Android中编译工具链的改动----LLVM份量的增加
    DirectX10一矩阵代数(二)
    DirectX10一向量代数(一)
    基于asp.net + easyui框架,一步步学习easyui-datagrid——实现添加、编辑、删除(三)
  • 原文地址:https://www.cnblogs.com/guangheli/p/10906486.html
Copyright © 2011-2022 走看看