• Codeforces补题2020.3.4 (Round620 Div2)


    A.Two Rabbits

    Gildong厌倦了参加过多次Codeforce攻击,决定在公园休息一下。他坐在长凳上,很快他发现两只兔子在跳来跳去。一只兔子比另一只更高。

    他注意到两只兔子在互相跳来跳去。两只兔子的位置可以表示为水平线上的整数坐标。较高的兔子当前位于位置x,而较短的兔子当前位于位置y(x <y)。每秒钟,每只兔子跳到另一个位置。较高的兔子跳向a的正向,而较短的兔子跳向b的负向。

    例如,假设x = 0,y = 10,a = 2和b = 3。在第1秒,每只兔子将在位置2和7。在第2秒,两只兔子将在位置4。

    Gildong现在在想:两只兔子会在同一时刻处于同一位置吗?如果是这样,需要多长时间?让我们找到一个时间点(以秒为单位),在那之后兔子将处于同一点。

    输入值 每个测试包含一个或多个测试用例。第一行包含测试用例的数量t(1≤t≤1000)。

    每个测试用例仅包含一行。该行由四个整数x,y,a,b(0≤x<y≤109,1≤a,b≤109)-高兔子的当前位置,矮兔子的当前位置,跳跃距离高兔子的跳动距离和短兔子的跳动距离。

    输出量 对于每个测试用例,请打印一个整数:两只兔子在同一位置所花费的秒数。

    如果两只兔子永远不会同时在同一位置,请打印-1。

    题解:

    简单模拟

    #include<bits/stdc++.h>
    using namespace std;
    int a,b,x,y;
    int main () {
        int T;
        scanf("%d",&T);
        while (T--) {
            scanf("%d%d%d%d",&a,&b,&x,&y);
            if ((b-a!=0)&&(x+y==0)) {
                printf ("-1
    ");
                continue;
            }
            if (b-a==0) {
                printf ("0
    ");
                continue;
            }
            if ((b-a)%(x+y)==0) {
                printf ("%d
    ",(b-a)/(x+y));
                continue;
            }
            printf ("-1
    ");
        } 
        return 0;
    } 
    View Code

    B.Longest Palindrome

    回到解决问题的方向,吉尔东现在正在研究回文。他了解到回文是与反向字符串相同的字符串。例如,字符串“ pop”,“ noon”,“ x”和“ kkkkkk”是回文,而字符串“ moon”,“ tv”和“ abab”则不是。空字符串也是回文。

    Gildong非常喜欢这个概念,所以他想玩这个游戏。他有n个等长的m个不同的弦。他想丢弃某些字符串(可能没有或全部),并对其余的字符串重新排序,以使串联成为回文。他还希望回文期尽可能长。请帮助他找到一个。

    输入值 第一行包含两个整数n和m(1≤n≤100,1≤m≤50)-字符串数和每个字符串的长度。

    接下来的n行包含一个长度为m的字符串,仅由小写拉丁字母组成。所有字符串都是不同的。

    输出量 在第一行中,打印您制作的最长回文字符串的长度。

    在第二行中,打印该回文。如果有多个答案,请打印其中一个。如果回文为空,则打印空白行或根本不打印此行。

    题解:

    #include<bits/stdc++.h>
    using namespace std;
    int N,M;
    string s1,s2;
    unordered_set<string> st;
    int main () {
        scanf("%d%d",&N,&M);
        for (int i=0;i<N;i++) {
            string t;
            cin>>t;
            st.insert(t);
            string r=t;
            reverse(r.begin(),r.end());
            if (t==r) s1=t;
            else if (st.count(r)) 
                s2+=t;
        }
        string t=s2;
        reverse(t.begin(),t.end());
        s2+=s1+t;
        printf ("%d
    ",s2.length());
        cout<<s2<<"
    ";
        return 0;
    }
    View Code

    C.Air Conditioner

    吉东拥有一家烤肉餐厅。这家餐厅有很多顾客,所以很多人喜欢在参观之前进行预订。

    Gildong尽力满足客户需求,甚至还记住了所有客户的首选温度范围!通过查看预订列表,他想通过控制餐厅的温度来满足所有顾客的需求。

    该餐厅的空调有3种状态:关闭,加热和冷却。关闭时,餐厅的温度保持不变。加热时,温度在一分钟内升高1。最后,在冷却时,温度在一分钟内降低1。吉尔东可以在任何整数分钟内随意更改状态。空调最初关闭。

    每个客户都具有三个值:ti-第i位客户访问餐厅的时间(分钟),li-首选温度范围的下限,hi-首选温度范围的上限。

    如果顾客在去餐厅的那一刻温度在优选范围内,那么顾客会感到满意。正式地,第i个客户只有在第10分钟内温度在li和hi(含)之间时才满意。

    给定初始温度,保留客户的访问时间列表及其首选的温度范围,您将帮助他确定是否有可能满足所有客户的需求。

    输入值 每个测试包含一个或多个测试用例。第一行包含测试用例的数量q(1≤q≤500)。测试用例的说明如下。

    每个测试用例的第一行包含两个整数n和m(1≤n≤100,-109≤m≤109),其中n是预订客户的数量,m是餐厅的初始温度。

    接下来,n行。它们的第i行包含三个整数ti,li和hi(1≤ti≤109,−109≤li≤hi≤109),其中ti是第i个客户访问的时间,li是较低的hi是其首选温度范围的上限。hi是其首选温度范围的上限。优选的温度范围包括两端。

    客户的访问时间以不降序排列,当前时间为0。

    输出量 对于每个测试用例,如果有可能使所有客户满意,则打印“是”。否则,打印“否”。

    您可以在任何情况下(大写或小写)打印每个字母。

    题解:

    #include<bits/stdc++.h>
    using namespace std;
    int N,M;
    struct node {
        int t;
        int l;
        int r;
    };
    vector<node> vi;
    bool cmp (node a,node b) {
        if (a.t!=b.t) return a.t<b.t;
        else if (a.l!=b.l) return a.l<b.l;
        else return a.r<b.r;
    }
    void solve () {
        vi.clear();
        scanf("%d%d",&N,&M);
        int L=M,R=M;
        for (int i=0;i<N;i++) {
            int t,l,r;
            scanf("%d%d%d",&t,&l,&r);
            vi.push_back({t,l,r});
        }
        sort(vi.begin(),vi.end(),cmp);
        for (int i=0;i<N;i++) {
            int t=vi[i].t;
            if (i!=0) t-=vi[i-1].t;
            L=max(L-t,vi[i].l);
            R=min(R+t,vi[i].r);
            if (L>R) {
                printf ("NO
    ");
                return;
            }
        }
        printf ("YES
    ");
    }
    int main () {
        int T;
        scanf("%d",&T);
        while (T--) solve();
        return 0;
    }
    View Code

    D.Shortest and Longest LIS

    Gildong最近学习了如何在O(nlogn)时间中找到长度为n的序列中最长的递增子序列(LIS)。他想测试自己是否可以正确实施,但是他找不到任何在线法官可以做到(即使实际上有很多法官)。因此,相反,他将为您做一个关于在1到n之间(含1和n)的n个不同整数进行排列的测验,以用您的输出测试他的代码。

    测验如下。

    Gildong提供了一个长度为n-1的字符串,仅由字符“ <”和“>”组成。第i个(1索引)字符是序列中第i个元素和第i + 1个元素之间的比较结果。如果字符串的第i个字符是“ <”,则序列中的第i个元素小于第i + 1个元素。如果字符串的第i个字符是'>',则序列中的第i个元素大于第i + 1个元素。

    他希望您找到两个可能的序列(不一定是不同的),这些序列由介于1和n之间(含端点)的n个不同的整数组成,每个整数都满足比较结果,其中第一个序列的LIS长度最小,而第一个序列的LIS长度最小。第二序列的LIS是最大可能的。

    输入值 每个测试包含一个或多个测试用例。第一行包含测试用例的数量t(1≤t≤104)。

    每个测试用例仅包含一行,该行由一个整数和一个仅由字符“ <”和“>”组成的字符串组成。整数是n(2≤n≤2⋅105),这是您需要查找的排列的长度。该字符串是描述中说明的比较结果。字符串的长度为n-1。

    确保所有测试用例中所有n的总和不超过2⋅105。

    输出量 对于每个测试用例,打印两行,每行n个整数。第一行是具有最小长度的LIS的序列,第二行是具有最大长度的LIS的序列。如果有多个答案,请打印其中一个。每个序列应包含1到n之间的所有整数(含1和n),并且应满足比较结果。

    可以证明,至少存在一个答案。

    题解:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+14;
    int T;
    int N;
    int p[maxn];
    char s[maxn];
    int main () {
        scanf("%d",&T);
        while (T--) {
            scanf("%d%s",&N,s+1);
            for (int i=1;i<=N;i++) 
                p[i]=N-i+1;
            for (int i=1;i<N;) {
                int j=i;
                while (s[j]=='<') j++;
                reverse(p+i,p+j+1);
                i=j+1;
            }
            for (int i=1;i<=N;i++) 
                printf ("%d ",p[i]);
            printf ("
    ");
            for (int i=1;i<=N;i++)
                p[i]=i;
            for (int i=1;i<N;) {
                int j=i;
                while (s[j]=='>') j++;
                reverse(p+i,p+j+1);
                i=j+1;
            } 
            for (int i=1;i<=N;i++) 
                printf ("%d ",p[i]);
            printf ("
    ");
        }
        return 0;
    } 
    View Code

    E.1-Trees and Queries

    吉尔东(Gildong)正在远足一座山,在数以百万计的树木中行走。受到他们的启发,他突然想出了一个关于数据结构树的有趣想法:如果我们在树中添加另一条边怎么办?

    然后他发现这种树状图称为1树。由于Gildong厌倦了解决太多树木问题的工作,他想看看是否也可以在1棵树中使用类似的树木技术。他将通过在1树上提供查询来测试您,而不是自己解决问题。

    首先,他将为您提供一棵具有n个顶点的树(非1树),然后他会问您q个查询。每个查询包含5个整数:x,y,a,b和k。这意味着在顶点x和y之间添加双向边后,系统会要求您确定是否存在从顶点a到b的路径,该路径正好包含k个边。路径可以多次包含相同的顶点和相同的边。所有查询彼此独立;即在查询中添加的边在下一个查询中被删除。

    输入值 第一行包含整数n(3≤n≤105),即树的顶点数。

    接下来的n-1行分别包含两个整数u和v(1≤u,v≤n,u≠v),这意味着顶点u和v之间存在一条边。所有边都是双向且互不相同的。

    下一行包含整数q(1≤q≤105),这是Gildong要询问的查询数。

    接下来的q行分别包含五个整数x,y,a,b和k(1≤x,y,a,b≤n,x≠y,1≤k≤109)–在说明中说明的整数。可以确保原始树中不存在x和y之间的边。

    输出量 对于每个查询,如果在x和y顶点之间添加了一条边后,如果存在一条路径,该路径恰好包含从顶点a到b的k条边,则打印“ YES”。否则,打印“否”。

    您可以在任何情况下(大写或小写)打印每个字母。

    题解:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+14;
    int N,Q;
    int father[18][maxn];
    int h[maxn];
    vector<int> g[maxn];
    void dfs (int x) {
        for (int i=0;i<g[x].size();i++) {
            int v=g[x][i];
            if (v==father[0][x]) continue;
            father[0][v]=x;
            h[v]=h[x]+1;
            dfs(v);
        }
    }
    int lca (int x,int y) {
        if (h[x]<h[y]) swap(x,y);
        for (int i=17;i>=0;i--) {
            if (h[x]-h[y]>>i) x=father[i][x];
        }
        if (x==y) return x;
        for (int i=17;i>=0;i--) {
            if (father[i][x]!=father[i][y]) {
                x=father[i][x];
                y=father[i][y];
            }
        }
        return father[0][x];
    }
    int getDis (int x,int y) {
        return h[x]+h[y]-h[lca(x,y)]*2;
    }
    bool check (int x,int y) {
        return y>=x&&x%2==y%2; 
    }
    int main () {
        scanf("%d",&N);
        for (int i=1;i<N;i++) {
            int a,b;
            scanf("%d%d",&a,&b);
            g[a].push_back(b);
            g[b].push_back(a);
        }
        dfs(1);
        for (int i=1;i<=17;i++) {
            for (int j=1;j<=N;j++) 
                father[i][j]=father[i-1][father[i-1][j]];
        }
        scanf("%d",&Q);
        for (int i=0;i<Q;i++) {
            int x,y,a,b,k;
            scanf("%d%d%d%d%d",&x,&y,&a,&b,&k);
            if (check(getDis(a,b),k)||
                check(getDis(a,x)+getDis(y,b)+1,k)||
                check(getDis(a,y)+getDis(x,b)+1,k)) 
                printf ("YES
    ");
            else printf ("NO
    ");
        }
        return 0;
    }
    View Code

    F.Animal Observation

    吉尔东(Gildong)喜欢观察动物,因此他购买了两个照相机,以拍摄森林中野生动物的视频。一台摄像机的颜色是红色,另一台摄像机的颜色是蓝色。

    从第1天到第n天,Gildong将拍摄n天的视频。森林可以分为m个区域,编号从1到m。他将通过以下方式使用相机:

    在每个奇数天(1日,3日,5日...),将红色相机带到森林中并录制2天的视频。 在每天的偶数日(第2、4、6等),将蓝色相机带到森林中并录制2天的视频。 如果他在第n天使用其中一台摄像机开始录制,则该摄像机仅录制一天。 每个摄像机可以观察森林的k个连续区域。例如,如果m = 5且k = 3,则他可以放置相机观察这三个区域范围之一,持续两天:[1,3],[2,4]和[3,5]。

    Gildong获得了有关每天在每个区域看到多少动物的信息。由于他想观察尽可能多的动物,因此他希望您找到放置两台摄像机n天的最佳方法。请注意,如果两个摄像机在同一天观察同一区域,则在该区域观察到的动物仅被计数一次。

    输入值 第一行包含三个整数n,m和k(1≤n≤50、1≤m≤2⋅104、1≤k≤m)– Gildong将要记录的天数,森林,以及摄像机的范围。

    接下来的n行每个包含m个整数。第i + 1行中的第j个整数是在第j个区域的第i天可以看到的动物数量。动物的数量在0到1000之间(含0和1000)。

    输出量 打印一个整数-可以观察到的最大动物数量。

    题解:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=20014;
    struct node {
        int l;
        int r;
        int mx;
        int tag;
    }segTree[maxn*4];
    int N,M,K;
    int a[60][maxn];
    int sum[60][maxn];
    int dp[60][maxn];
    void build (int i,int l,int r,int x) {
        segTree[i].l=l;
        segTree[i].r=r;
        segTree[i].tag=0;
        if (l==r-1) 
            segTree[i].mx=dp[x-1][l]+sum[x][l+K-1]-sum[x][max(K-1,l-1)];
        else {
            int mid=(l+r)>>1;
            build(i<<1,l,mid,x);
            build(i<<1|1,mid,r,x);
            segTree[i].mx=max(segTree[i<<1].mx,segTree[i<<1|1].mx);
        }
    }
    void update (int i) {
        segTree[i<<1].mx+=segTree[i].tag;
        segTree[i<<1|1].mx+=segTree[i].tag;
        segTree[i<<1].tag+=segTree[i].tag;
        segTree[i<<1|1].tag+=segTree[i].tag;
        segTree[i].tag=0;
    }
    void modify (int i,int l,int r,int del) {
        if (l<=segTree[i].l&&r>=segTree[i].r) {
            segTree[i].mx+=del;
            segTree[i].tag+=del;
            return; 
        }
        if (segTree[i].tag) update(i);
        int mid=(segTree[i].l+segTree[i].r)>>1;
        if (l<mid) modify(i<<1,l,r,del);
        if (r>mid) modify(i<<1|1,l,r,del);
        segTree[i].mx=max(segTree[i<<1].mx,segTree[i<<1|1].mx);
    }
    void solve () {
        scanf("%d%d%d",&N,&M,&K);
        for (int i=1;i<=N;i++) {
            sum[i][0]=0;
            for (int j=1;j<=M;j++) {
                scanf("%d",&a[i][j]);
                sum[i][j]=sum[i][j-1]+a[i][j];
            }
        }
        for (int j=1;j<=M-K+1;j++) 
            dp[1][j]=sum[1][j+K-1]-sum[1][j-1];
        for (int i=2;i<=N;i++) {
            build(1,1,M-K+2,i);
            for (int j=1;j<=M-K+1;j++) {
                modify(1,j,j+K,-a[i][j+K-1]);
                dp[i][j]=segTree[1].mx+sum[i][j+K-1]-sum[i][j-1];
                modify(1,max(j-K+1,1),j+1,a[i][j]);
            }
        }
        int ans=dp[N][1];
        for (int j=2;j<=M;j++) 
            ans=max(ans,dp[N][j]);
        printf ("%d
    ",ans);
    }
    int main () {
        solve();
        return 0;
    }
    View Code
  • 相关阅读:
    BZOJ2034 【2009国家集训队】最大收益
    「PKUSC2018」最大前缀和
    「PKUSC2018」真实排名
    【FJOI2016】建筑师
    【FJOI2014】最短路径树问题
    【HNOI2007】紧急疏散
    【TJOI2015】线性代数
    【SDOI2017】新生舞会
    POJ2079 Triangle
    【SDOI2011】工作安排
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/12407535.html
Copyright © 2020-2023  润新知