zoukankan      html  css  js  c++  java
  • Codeforces Round #397 by Kaspersky Lab and Barcelona Bootcamp (Div. 1 + Div. 2 combined)

    运气好,分到的房里我最先开始Hack C题,Hack了12个,听说F题沙雕莫队但我不会,最后剩不到15分钟想出E题做法打了一波结果挂了,最后虽然上分了但总有点不甘心。

    最后A掉ABCD Hack+12 Rank:176 Rating:2109+47->2156

    上次被黄学长D:“怎么说你也有2200了吧”,2100蒟蒻真是抱歉QAQ

    A.Neverending competitions

    题目大意:某人从家里飞出去再飞回来再飞出去再飞回来……,现在给你N张他用过的机票(N<=100),保证合法但顺序打乱了,问他现在家还是在外面。

    思路:n%2问题……没看清题目保证在外地必然飞回家,写了判断出入度。

    #include<cstdio>
    inline int read()
    {
        int x=0;char c;
        while((c=getchar())<'0'||c>'9');
        for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    int main()
    {
        int n=read(),x,a=0;char s[10];
        scanf("%s",s);x=(s[0]*1000+s[1])*1000+s[2];
        while(n--)
        {
            scanf("%s",s);
            if((s[0]*1000+s[1])*1000+s[2]==x)++a;
            if((s[5]*1000+s[6])*1000+s[7]==x)--a;
        }
        puts(a?"contest":"home");
    }

    B.Code obfuscation

    题目大意:一篇文章,碰见第一个没碰过的单词就把所有这个单词替换成a,第二个就替换成b,给一个长度不超过500的小写字母串,问是否可能是某篇文章加密得到的。

    思路:拿个变量存用到哪个字母了呗……手速题

    #include<cstdio>
    inline int read()
    {
        int x=0;char c;
        while((c=getchar())<'0'||c>'9');
        for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 500
    char s[MN+5];
    int main()
    {
        int i,x='a';
        scanf("%s",s);
        for(i=0;s[i];++i)
        {
            if(s[i]>x)return 0*puts("NO");
            if(s[i]==x)++x;
        }
        puts("YES");
    }

    C.Table Tennis Game 2

    题目大意:给出a,b,k,问(a,b)最多被分解为几个(k,x)或(x,k)(x<k)的和,若无解输出-1。

    思路:判断是否有解然后输出a/k+b/k就行了,怎么判断有解就变成了本场比赛最大的hack点,正确做法是(a<k&&b%k!=0)||(b<k&&a%k!=0)就无解,错误做法有a/k+b/k>0就有解,a<k且b<k时无解等。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x=0;char c;
        while((c=getchar())<'0'||c>'9');
        for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    int main()
    {
        int k,a,b,ans;
        k=read();a=read();b=read();
        if(a<k&&b%k)return 0*puts("-1");
        if(b<k&&a%k)return 0*puts("-1");
        printf("%d",a/k+b/k);
    }

    D.Artsem and Saunders

    题目大意:N<=100,000,给出[1,n]到[1,n]的映射f(x),求[1,n]到[1,m]的映射g(x)和[1,m]到[1,n]的映射h(x),使得任意x属于[1,m]g(h(x))=x,任意x属于[1,n]h(g(x))=f(x)。

    思路:观察发现对于每组相等的f(x)的x,必须要有一个满足x=f(x),这些x全部映射到[1,m]中一个再映射到f(x)就行了。

    #include<cstdio>
    inline int read()
    {
        int x=0;char c;
        while((c=getchar())<'0'||c>'9');
        for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 100000
    int a[MN+5],c[MN+5],p[MN+5],pn;
    int main()
    {
        int n=read(),i;
        for(i=1;i<=n;++i)if((a[i]=read())==i)p[c[i]=++pn]=i;
        for(i=1;i<=n;++i)if(!c[a[i]])return 0*puts("-1");
        printf("%d
    ",pn);
        for(i=1;i<=n;++i)printf("%d ",c[a[i]]);puts("");
        for(i=1;i<=pn;++i)printf("%d ",p[i]);
    }

    E.Tree Folding

    题目大意:一颗树,每次选一个点,把与他相连的两条同长的链并成一条(链上不能向其他地方连),问最后能否把树并成一条链,能的话求出最短链长。

    思路:我瞎yy了一个做法,不会证明,请随意意会。求出每个点作为根时他每个儿子的子树深度,如果深度的种数超过2则无解,若全部都不超过2则答案为每个点为根时得到的两种深度相加中的最小值,算深度可以DP O(n)求出以1为根的情况然后O(1)移动根。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 200000
    struct edge{int nx,t;}e[MN*2+5];
    int h[MN+5],en,d[MN+5],d1[MN+5],d2[MN+5],c[MN+5],g;
    inline void ins(int x,int y)
    {
        e[++en]=(edge){h[x],y};h[x]=en;
        e[++en]=(edge){h[y],x};h[y]=en;
    }
    void cal(int x,int d)
    {
        if(!d1[x])d1[x]=d;else if(d1[x]!=d)
        if(!d2[x])d2[x]=d;else if(d2[x]!=d)g=1;
    }
    void pre(int x,int f)
    {
        for(int i=h[x];i;i=e[i].nx)if(e[i].t!=f)
        {
            pre(e[i].t,x);
            if(d[e[i].t]>=d[x])c[x]=d[x],d[x]=d[e[i].t];
            else if(d[e[i].t]>c[x])c[x]=d[e[i].t];
            cal(x,d[e[i].t]);
        }
        ++d[x];++c[x];
    }
    void dfs(int x,int f,int fd)
    {
        if(f)cal(x,fd);
        for(int i=h[x];i;i=e[i].nx)if(e[i].t!=f)
            dfs(e[i].t,x,max(fd+1,d[x]==d[e[i].t]+1?c[x]:d[x]));
    }
    int main()
    {
        int n=read(),i,ans;
        for(i=1;i<n;++i)ins(read(),read());
        pre(1,0);dfs(1,0,0);
        if(g)return 0*puts("-1");
        for(ans=d1[1]+d2[1],i=2;i<=n;++i)ans=min(ans,d1[i]+d2[i]);
        while(ans%2==0)ans/=2;
        printf("%d",ans);
    }

    F.Souvenirs

    题目大意:给定一个长度为N的数列,M次询问,每次询问区间中最小的两个不同位置元素的最小差,区间长度至少为2。(N<=100,000,M<=300,000)

    思路:觉得这题非常厉害,今天终于把这坑填了(这位置好深,不知道有没人看得到)。好多人写的玄学莫队,甚至多个log的都卡过去了。从网上某大神处找到了O(Nlogn^2+Mlogn)的解法,非常妙,大概是这样的:考虑从左到右加入数字,维护以当前加到的数字为右端点,各个左端点的答案。分两次做,一次只考虑前面的数小于后面的情况,另一次只考虑大于。这里说下第一种(另一种一样,反过来就好了):每次加入一个数ai,我们找到已加入的最右端的小等于ai的数aj,用ai-aj更新1~j作为左端点时的答案,接下来考虑再用aj左边小等于ai的数ak来更新,若用ak更新有意义,则必然ai-ak<ai-aj,即ak>aj,这里有个巧妙的性质,即如果ai-ak>ak-aj,我们可以不必更新k,因为更优的ak-aj必然会在我们做大于的时候被考虑到,也就是说,ak不仅要大于aj,还要大于(ai+aj)/2,这样我们每次更新最右的一个k后,下一个ak能取的范围必然缩小一半,也就是每次加入ai,最多只用更新log次!我们用线段树维护答案,权值线段树维护当前已加入的某数字最右端的位置,问题就迎刃而解啦。

    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<algorithm>
    using namespace std;
    char B[1<<26],*S=B,C;int X;
    inline int read()
    {
        while((C=*S++)<'0'||C>'9');
        for(X=C-'0';(C=*S++)>='0'&&C<='9';)X=(X<<3)+(X<<1)+C-'0';
        return X;
    }
    #define MN 100000
    #define MQ 300000
    #define N 131072
    int a[MN+5],p[MN+5],c[MN+5],cn,ans[MQ+5];
    int t1[N*2+5],t2[N*2+5];
    vector<pair<int,int> > v[MN+5];
    void renew(int l,int r,int x)
    {
        for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1)t1[l+1]=min(t1[l+1],x);
            if( r&1)t1[r-1]=min(t1[r-1],x);
        }
    }
    int query(int k)
    {
        int r=t1[k+=N];
        while(k>>=1)r=min(r,t1[k]);
        return r;
    }
    void renew(int k,int x){for(k+=N;k;k>>=1)t2[k]=max(t2[k],x);}
    int query(int l,int r)
    {
        int res=0;
        for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1)res=max(res,t2[l+1]);
            if( r&1)res=max(res,t2[r-1]);
        }
        return res;
    }
    int main()
    {
        fread(B,1,1<<26,stdin);
        int n=read(),q,i,j,k;
        for(i=1;i<=n;++i)a[i]=c[i]=read();
        sort(c+1,c+n+1);
        for(i=2,cn=1;i<=n;++i)if(c[i]!=c[cn])c[++cn]=c[i];
        for(i=1;i<=n;++i)p[i]=lower_bound(c+1,c+cn+1,a[i])-c;
        for(q=read(),i=0;i<q;++i)j=read(),v[read()].push_back(make_pair(i,j));
        memset(ans,127,sizeof(ans));memset(t1,127,sizeof(t1));
        for(i=1;i<=n;++i)
        {
            for(j=1;j<=p[i]&&(k=query(j,p[i]));)
                renew(1,k,a[i]-a[k]),j=upper_bound(c+1,c+cn+1,(a[i]+a[k])>>1)-c;
            for(j=0;j<v[i].size();++j)
                ans[v[i][j].first]=min(ans[v[i][j].first],query(v[i][j].second));
            renew(p[i],i);
        }
        memset(t1,127,sizeof(t1));memset(t2,0,sizeof(t2));
        for(i=1;i<=n;++i)
        {
            for(j=cn;j>=p[i]&&(k=query(p[i],j));)
                renew(1,k,a[k]-a[i]),j=lower_bound(c+1,c+cn+1,(a[i]+a[k]+1)>>1)-c-1;
            for(j=0;j<v[i].size();++j)
                ans[v[i][j].first]=min(ans[v[i][j].first],query(v[i][j].second));
            renew(p[i],i);
        }
        for(i=0;i<q;++i)printf("%d
    ",ans[i]);
    }
  • 相关阅读:
    转载:史上最全|阿里那些牛逼带闪电的开源工具,你知道几个?
    互怼、IPO、雷潮、寒冬,2018 互联网圈的那些事儿
    微信迎来又一次重大改版 7.0 版本
    公众号文章目录
    聊几个与赚钱相关的小事情
    使用docker Registry快速搭建私有镜像仓库
    开源组件ELK日志系统配置与管理
    Mysql MHA高可用集群架构
    强大的开源企业级数据监控利器Lepus安装与配置管理
    关于下载gitbash客户端
  • 原文地址:https://www.cnblogs.com/ditoly/p/CF397.html
Copyright © 2011-2022 走看看