• HGOI 20191030am 题解


    Problem A 腿部挂件

      给出$n$个数的序列$a_i$,支持$T$次操作。

      每次操作形如$x , l , r$,计算$max_{i = l}^{r} (a_i oplus x)$的值。

      对于$100\%$的数据满足$1 leq n leq 2 imes 10^5 , 0 leq a_i leq 10^9$

    Solution : 

      通常可以使用可持久化字典树求解,但是这里可以用字典树套vector来做。

      这样当当前节点vector有一个在$l,r$的数中就往下走,还是按照以前的贪心策略,从高位到低位贪心。

      这样做的时间复杂度是$O(n {log_2} ^2 n)$

    #include<bits/stdc++.h>
    #define pb push_back
    using namespace std;
    struct node
    {
        vector<int>p;
        int ls,rs;
        node(){ls=rs=-1;}
    }tr[6100000];
    int n,m,a,x,y,cnt,o[50];
    void push(int k,int p)
    {
        for(int i=30-1,nw=1;i>=0;i--)
        {
            if(k&o[i])
            {
                if(tr[nw].ls==-1)tr[nw].ls=++cnt;
                nw=tr[nw].ls;
            }
            else
            {
                if(tr[nw].rs==-1)tr[nw].rs=++cnt;
                nw=tr[nw].rs;
            }
            tr[nw].p.pb(p);
        }
    }
    int query(int k,int l,int r)
    {
        int ans=0;
        for(int i=30-1,nw=1;i>=0;i--)
        {
            if(k&o[i])
            {
                if(tr[nw].rs==-1||*(tr[tr[nw].rs].p.end()-1)<l||*lower_bound(tr[tr[nw].rs].p.begin(),tr[tr[nw].rs].p.end(),l)>r)
                    nw=tr[nw].ls,ans+=o[i];
                else nw=tr[nw].rs;
            }
            else
            {
                if(tr[nw].ls==-1||*(tr[tr[nw].ls].p.end()-1)<l||*lower_bound(tr[tr[nw].ls].p.begin(),tr[tr[nw].ls].p.end(),l)>r)
                    nw=tr[nw].rs;
                else nw=tr[nw].ls,ans+=o[i];
            }
        }
        return ans^k;
    }
    int main()
    {
        freopen("hugclose.in","r",stdin);
        freopen("hugclose.out","w",stdout);
        scanf("%d%d",&n,&m),o[0]=cnt=1;
        for(int i=1;i<30;i++)o[i]=o[i-1]*2;
        for(int i=1;i<=n;i++)scanf("%d",&a),push(a,i);
        for(int i=1;i<=m;i++)scanf("%d%d%d",&a,&x,&y),printf("%d
    ",query(a,x+1,y+1));
        return 0;
    }
    hugclose.cpp

    Problem B 走夜路

      一条直线上有n+1个充电站,一开始你在第一个充电站,每个充电站都能以某个代价充电

      每走一个单位距离就要耗费一单位电,求按顺序走完所有充电站的最小代价

      对于$100\%$的数据满足$1 leq n leq 5 imes 10^5$

    Solution  :

       考虑一种贪心,依次考虑每一个充电站。

       下一个充电站优先级从高到低依次是:

    • 当前充电站以后第一个费用小于当前充电站(此时,直接在当前充电站充满恰好能到下个充电站的电,然后直接走到那个充电站即可)
    • 终点(如果当前充电站冲一定的点之后能到终点,那么就直接到达终点)
    • 在充满电后能走到的所有充电站中,费用最小的充电站(此时需要先在当前充电站充满电后再移动)

      可以考虑使用单调栈来求对于每个位置右侧第一个小于它的数,(从前往后加入数,满足栈单调增,弹栈的时候记录即可)

      然后再使用小常数的$st$表来求出静态区间最小值并且维护标号。

      所以,本题就是$O(n log_2 n)$的复杂度了。

    #pragma GCC optimize(3)
    # include <bits/stdc++.h>
    using namespace std;
    const int N=500000+10;
    int st[1<<20][20],id[1<<20][20];
    # define int long long 
    int n,T,d[N],a[N],r[N];
    stack<int>s;
    int dist(int x,int y) { if (x>y) swap(x,y); return d[y-1]-d[x-1];}
    namespace fast_IO{
        const int IN_LEN = 10000000, OUT_LEN = 10000000;
        char ibuf[IN_LEN], obuf[OUT_LEN], *ih = ibuf + IN_LEN, *oh = obuf, *lastin = ibuf + IN_LEN, *lastout = obuf + OUT_LEN - 1;
        inline char getchar_(){return (ih == lastin) && (lastin = (ih = ibuf) + fread(ibuf, 1, IN_LEN, stdin), ih == lastin) ? EOF : *ih++;}
        inline void putchar_(const char x){if(oh == lastout) fwrite(obuf, 1, oh - obuf, stdout), oh = obuf; *oh ++= x;}
        inline void flush(){fwrite(obuf, 1, oh - obuf, stdout);}
        int read(){
            int x = 0; int zf = 1; char ch = ' ';
            while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar_();
            if (ch == '-') zf = -1, ch = getchar_();
            while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar_(); return x * zf;
        }
        void write(int x){
            if (x < 0) putchar_('-'), x = -x;
            if (x > 9) write(x / 10);
            putchar_(x % 10 + '0');
        }
    }
    using namespace fast_IO;
    void build() {
        memset(st,0x3f,sizeof(st));
        for (int i=1;i<=n;i++) st[i][0]=a[i],id[i][0]=i;
        for (int i=1;i<=19;i++)
            for (int j=1;j<=n;j++)
                if (st[j][i-1]<st[j+(1<<(i-1))][i-1]) {
                    st[j][i] = st[j][i-1];
                    id[j][i] = id[j][i-1];
                } else {
                    st[j][i] = st[j+(1<<(i-1))][i-1];
                    id[j][i] = id[j+(1<<(i-1))][i-1];
                }
    }
    int LOG[N];
    int query(int l,int r) {
        int k=LOG[r-l+1];
        if (st[l][k] < st[r-(1<<k)+1][k]) return id[l][k]; 
        else return id[r-(1<<k)+1][k];
    }
    signed main()
    {
        n=read();T=read();
        for (int i=1;i<=n;i++) LOG[i] = log2(i);
        for (int i=1;i<=n;i++) d[i]=read(),a[i]=read();
        build();
        while (!s.empty()) s.pop();
        for (int i=n;i>=1;i--) {
            while (!s.empty()&&a[s.top()]>=a[i]) s.pop();
            if (s.empty()) r[i]=n; else r[i]=s.top()-1;
            s.push(i);
        }
        for (int i=1;i<=n;i++) 
            r[i] = (r[i]==n)?(-1):(r[i]+1),
            d[i] += d[i-1];
        int now = 1, res = 0;
        int cost = 0;
        while (true) { 
            if (r[now]!=-1 && dist(r[now] , now) <= T) {
                if (res >= dist(r[now], now)) res-=dist(r[now],now);
                else  cost +=  1ll * a[now]*(dist(r[now], now)-res),res = 0;
                now = r[now];
            } else if (dist(n+1,now) <= T) {
                if (res >= dist(n+1, now)) res-=dist(n+1,now);
                else cost += 1ll * a[now]*(dist(n+1,now)-res),res = 0;
                break;
            } else {
                cost += 1ll * (T-res)*a[now];
                int l = now+1, r = n , ans = -1;
                while (l<=r) {
                    int mid = (l+r) >> 1;
                    if (dist(mid,now)<=T) ans=mid,l=mid+1;
                    else r = mid-1;
                }
                if (ans == -1) {
                    write(-1); flush(); return 0;
                }
                int to = query(now+1,ans);
                res = T - dist(to , now);
                now = to;
            }
        }
        write(cost);  flush(); 
        return 0;
    }
    wayhome.cpp

    Problem C 宝石专家

     给出$n$个数的序列$a_i$,处理$T$个询问,

     每个询问形如$l,r$,请输出在$a_l ... a_r$中两个相同的数的最近距离。

     若$a_x = a_y$,那么距离定义为$|x- y|$

     对于$100\%$的数据,满足$1 leq n,Tleq 2 imes 10^5$

    Solution : 

      首先,我们发现对于相同的数,在一些位置,只有相邻的两个数所构成的线段有意义。

      所以需要处理的小线段长度在$n$这个级别。

      我们考虑将操作离线,放在一个$[1,n]$的数轴上,并考虑从$n$到$1$依次扫。

      如果当前遇到了一个小线段的左端点$l$,那么在线段树中$[r,n]$用这条线段的权值$r-l$来更新答案。

      所以,线段树的意义是扫到当前位置,询问线段的右端点的答案。

      所以,如果遇到一个询问线段,那么直接求出$[l,r]$的最小值即可,但是由于值的单调性,直接单点求出$r$的值即可。

      时间复杂度就是$O(n log_2 n)$。

    #pragma GCC optimize(3)
    # include <bits/stdc++.h>
    # define inf (0x3f3f3f3f)
    using namespace std;
    const int N = 2e5 + 10;
    vector<int>tmp;
    vector<int>v[N];
    vector< pair<int,int> >r[N],qes[N];
    int n,m,a[N],ans[N];
    namespace fast_IO{
        const int IN_LEN = 10000000, OUT_LEN = 10000000;
        char ibuf[IN_LEN], obuf[OUT_LEN], *ih = ibuf + IN_LEN, *oh = obuf, *lastin = ibuf + IN_LEN, *lastout = obuf + OUT_LEN - 1;
        inline char getchar_(){return (ih == lastin) && (lastin = (ih = ibuf) + fread(ibuf, 1, IN_LEN, stdin), ih == lastin) ? EOF : *ih++;}
        inline void putchar_(const char x){if(oh == lastout) fwrite(obuf, 1, oh - obuf, stdout), oh = obuf; *oh ++= x;}
        inline void flush(){fwrite(obuf, 1, oh - obuf, stdout);}
        int read(){
            int x = 0; int zf = 1; char ch = ' ';
            while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar_();
            if (ch == '-') zf = -1, ch = getchar_();
            while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar_(); return x * zf;
        }
        void write(int x){
            if (x < 0) putchar_('-'), x = -x;
            if (x > 9) write(x / 10);
            putchar_(x % 10 + '0');
        }
    }
    using namespace fast_IO;
    struct Seg {
        int val,tag;
        Seg() { val = tag = inf;}
    }tr[N<<2];
    # define lson ls,l,mid
    # define rson rs,mid+1,r
    # define mid (l+r>>1)
    # define ls (x<<1)
    # define rs (x<<1|1)
    void down(int x) {
        tr[ls].val=min(tr[ls].val,tr[x].tag);
        tr[rs].val=min(tr[rs].val,tr[x].tag);
        tr[ls].tag=min(tr[ls].tag,tr[x].tag);
        tr[rs].tag=min(tr[rs].tag,tr[x].tag);
        tr[x].tag = inf;
    }
    void update(int x,int l,int r,int opl,int opr,int val) {
        if (opl <= l && r <= opr) {
            tr[x].tag = min(tr[x].tag , val);
            tr[x].val = min(tr[x].val , val);
            return;
        }
        down(x);
        if (opl<=mid) update(lson,opl,opr,val);
        if (opr> mid) update(rson,opl,opr,val);
        tr[x].val = min(tr[ls].val , tr[rs].val);
    }
    int query(int x,int l,int r,int pos) {
        if (l == r) return tr[x].val;
        down(x);
        if (pos<=mid) return query(lson,pos);
        else return query(rson,pos);
    }
    int main()
    {
        n=read();m=read(); 
        for (int i=1;i<=n;i++) {
            tmp.push_back(a[i]=read());
        }
        sort(tmp.begin(),tmp.end());
        tmp.erase(unique(tmp.begin(),tmp.end()),tmp.end());
        for (int i=1;i<=n;i++) {
            a[i] = lower_bound(tmp.begin(),tmp.end(),a[i]) - tmp.begin()+1;
            v[a[i]].push_back(i);
        }
        for (int i=1;i<=n;i++) {
            if (v[i].size() < 2) continue;
            for (int j=0;j<v[i].size()-1;j++)
                r[v[i][j]].push_back(make_pair(v[i][j+1],v[i][j+1]-v[i][j])); 
        }
        for (int i=1;i<=m;i++) {
            int l=read(),r=read(); 
            qes[l].push_back(make_pair(r,i));
        }
        for (int i=n;i>=1;i--) {
            int sz = r[i].size();
            if (sz) {
                for (int j=0;j<sz;j++) 
                    update(1,1,n,r[i][j].first,n,r[i][j].second);
            }
            sz = qes[i].size();
            if (sz) {
                for (int j=0;j<sz;j++)
                 ans[qes[i][j].second] = query(1,1,n,qes[i][j].first);
            }
        }
        for (int i=1;i<=m;i++) {
            write((ans[i]>=inf)?-1:ans[i]); putchar_('
    ');
        }
        flush();
        return 0;
    }
    jewel.cpp
  • 相关阅读:
    也用一下Windows Live Writer
    常用16种iOS视图切换动画
    iPad平板电脑程序开发基础规则(源址:http://www.cocoachina.com/bbs/simple/?t82559.html)
    NSXMLParser详解
    UIScrollView用法
    使用UIActivityIndicatorView 和多线程
    为视图加边框
    iPhone SDK开发基础之iPhone程序框架
    NSXMLParser详解(事例)
    iOS开发 小知识点
  • 原文地址:https://www.cnblogs.com/ljc20020730/p/11764775.html
Copyright © 2020-2023  润新知