Codeforces 765F. Souvenirs

版权声明:...............转载说一声并注明出处qaq............... https://blog.csdn.net/L_0_Forever_LF/article/details/79981123

每次询问一个区间内任意两个数差值绝对值的最小值

不妨考虑一个位置i,他和哪些位置j(j<i)匹配可能更新区间的答案
这里只考虑a[i]>a[j]的情况,另一种同理
可能贡献的j一定是一个下降子,另外还有一个不那么显然的性质,就是真正有用的j序列的长度不超过log w,因为假设(j,i)可以产生贡献,下一个贡献的位置是j,j<j,那么真正有用的j需要满足两个条件 aiaj<aiaj,aiaj<ajaj,否则(j,j)的贡献就优于(j,i)
那么可以发现,aiaj每次至少减一半,所以有用的j不超过log个,我们可以直接找出这logj和i组成可能产生贡献的点对
然后每个询问在二维平面上就是询问一个矩形内最小的点这样的东西

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;

inline void down(int &a,const int &b){if(a>b)a=b;}
inline void read(int &x)
{
    char c; while(!((c=getchar())>='0'&&c<='9'));
    x=c-'0';
    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';
}
int ch[10],chn;
inline void Output(int x)
{
    if(!x) { puts("0");return; }
    while(x) ch[++chn]=x%10,x/=10;
    while(chn) putchar('0'+ch[chn--]);
    putchar('\n');
}
const int maxn = 210000;
const int maxm = 1100000;

int n,m;
int a[maxn];
struct ct{int x;int *i;}s[maxn];
inline bool cmp(const ct x,const ct y){return x.x<y.x;}
int To[maxn],id;
void Trans()
{
    for(int i=1;i<=n;i++) s[i].x=a[i],s[i].i=&a[i];
    sort(s+1,s+n+1,cmp);
    for(int i=1,la=s[1].x-1;i<=n;la=s[i].x,i++)
    {
        if(la!=s[i].x) To[++id]=s[i].x;
        (*s[i].i)=id;
    }
}

struct segment
{
    int mx[maxn<<2];
    void init() { memset(mx,-1,sizeof mx); }
    void pushup(int x) { mx[x]=max(mx[x<<1],mx[x<<1|1]); }
    int loc,c;
    void upd(int x,const int l,const int r)
    {
        if(l==r) { mx[x]=c;return; }
        int mid=(l+r)>>1;
        if(loc<=mid) upd(x<<1,l,mid);
        else upd(x<<1|1,mid+1,r);
        pushup(x);
    }
    int lx,rx;
    int querymx(int x,const int l,const int r)
    {
        if(!x||rx<l||r<lx) return -1;
        if(lx<=l&&r<=rx) return mx[x];
        int mid=(l+r)>>1;
        return max(querymx(x<<1,l,mid),querymx(x<<1|1,mid+1,r));
    }
}seg;

struct segment2
{
    int seg[maxn<<2];
    int loc,lx,rx,c;
    void init() { memset(seg,63,sizeof seg); }
    void upd(int x,const int l,const int r)
    {
        if(rx<l||r<lx) return;
        if(lx<=l&&r<=rx) { down(seg[x],c);return; }
        int mid=l+r>>1;
        upd(x<<1,l,mid); upd(x<<1|1,mid+1,r);
    }
    int query(int x,const int l,const int r,int c)
    {
        down(c,seg[x]);
        if(l==r) return c;
        int mid=l+r>>1;
        if(loc<=mid) return query(x<<1,l,mid,c);
        else return query(x<<1|1,mid+1,r,c);
    }
}seg2;

int op[maxm],ans[maxm];
vector<int>V[maxn];

int main()
{
    read(n);
    for(int i=1;i<=n;i++) read(a[i]); Trans();
    read(m);
    for(int i=1;i<=m;i++) 
    {
        int l,r; read(l); read(r);
        op[i]=l;
        V[r].push_back(i);
    }

    seg.init(); seg2.init();
    for(int i=1;i<=n;i++)
    {
        int las,l,r;

        las=0; r=1;
        while(1)
        {
            l=r,r=a[i];
            while(l<=r)
            {
                int mid=l+r>>1;
                if(To[mid]>=las) r=mid-1;
                else l=mid+1;
            }++r;
            seg.lx=r,seg.rx=a[i];
            int k=seg.querymx(1,1,n); if(k==-1) break;
            seg2.lx=1,seg2.rx=k,seg2.c=To[a[i]]-To[a[k]]; seg2.upd(1,1,n);
            if(las==To[a[i]]) break;
            las=To[a[k]]+(To[a[i]]-To[a[k]]+1)/2;
            if(las>To[a[i]]) break;
        }

        las=To[id]; l=id;
        while(1)
        {
            r=l,l=a[i];
            while(l<=r)
            {
                int mid=l+r>>1;
                if(To[mid]<=las) l=mid+1;
                else r=mid-1;
            }--l;
            seg.lx=a[i],seg.rx=l;
            int k=seg.querymx(1,1,n); if(k==-1) break;
            seg2.lx=1,seg2.rx=k,seg2.c=To[a[k]]-To[a[i]]; seg2.upd(1,1,n);
            if(las==To[a[i]]) break;
            las=To[a[k]]-(To[a[k]]-To[a[i]]+1)/2;
            if(las<To[a[i]]) break;
        }

        seg.loc=a[i],seg.c=i; seg.upd(1,1,n);

        for(int j=0;j<(int)V[i].size();j++)
        {
            int ii=V[i][j];
            seg2.loc=op[ii];
            ans[ii]=seg2.query(1,1,n,inf);
        }
    }
    for(int i=1;i<=m;i++) Output(ans[i]);

    return 0;
}
阅读更多

Buy the souvenirs Buy the souvenirs

09-23

Problem DescriptionrnWhen the winter holiday comes, a lot of people will have a trip. Generally, there are a lot of souvenirs to sell, and sometimes the travelers will buy some ones with pleasure. Not only can they give the souvenirs to their friends and families as gifts, but also can the souvenirs leave them good recollections. All in all, the prices of souvenirs are not very dear, and the souvenirs are also very lovable and interesting. But the money the people have is under the control. They can’t buy a lot, but only a few. So after they admire all the souvenirs, they decide to buy some ones, and they have many combinations to select, but there are no two ones with the same kind in any combination. Now there is a blank written by the names and prices of the souvenirs, as a top coder all around the world, you should calculate how many selections you have, and any selection owns the most kinds of different souvenirs. For instance:rnrnrnrnrnAnd you have only 7 RMB, this time you can select any combination with 3 kinds of souvenirs at most, so the selections of 3 kinds of souvenirs are ABC (6), ABD (7). But if you have 8 RMB, the selections with the most kinds of souvenirs are ABC (6), ABD (7), ACD (8), and if you have 10 RMB, there is only one selection with the most kinds of souvenirs to you: ABCD (10).rn rnrnInputrnFor the first line, there is a T means the number cases, then T cases follow.rnIn each case, in the first line there are two integer n and m, n is the number of the souvenirs and m is the money you have. The second line contains n integers; each integer describes a kind of souvenir. rnAll the numbers and results are in the range of 32-signed integer, and 0<=m<=500, 0

Buy the souvenirs

05-26

Problem DescriptionnWhen the winter holiday comes, a lot of people will have a trip. Generally, there are a lot of souvenirs to sell, and sometimes the travelers will buy some ones with pleasure. Not only can they give the souvenirs to their friends and families as gifts, but also can the souvenirs leave them good recollections. All in all, the prices of souvenirs are not very dear, and the souvenirs are also very lovable and interesting. But the money the people have is under the control. They can’t buy a lot, but only a few. So after they admire all the souvenirs, they decide to buy some ones, and they have many combinations to select, but there are no two ones with the same kind in any combination. Now there is a blank written by the names and prices of the souvenirs, as a top coder all around the world, you should calculate how many selections you have, and any selection owns the most kinds of different souvenirs. For instance:nnnnnAnd you have only 7 RMB, this time you can select any combination with 3 kinds of souvenirs at most, so the selections of 3 kinds of souvenirs are ABC (6), ABD (7). But if you have 8 RMB, the selections with the most kinds of souvenirs are ABC (6), ABD (7), ACD (8), and if you have 10 RMB, there is only one selection with the most kinds of souvenirs to you: ABCD (10).n nnInputnFor the first line, there is a T means the number cases, then T cases follow.nIn each case, in the first line there are two integer n and m, n is the number of the souvenirs and m is the money you have. The second line contains n integers; each integer describes a kind of souvenir. nAll the numbers and results are in the range of 32-signed integer, and 0<=m<=500, 0

没有更多推荐了,返回首页