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\n");
            continue;
        }
        if (b-a==0) {
            printf ("0\n");
            continue;
        }
        if ((b-a)%(x+y)==0) {
            printf ("%d\n",(b-a)/(x+y));
            continue;
        }
        printf ("-1\n");
    }
    return 0;
} 

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\n",s2.length());
    cout<<s2<<"\n";
    return 0;
}

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\n");
            return;
        }
    }
    printf ("YES\n");
}
int main () {
    int T;
    scanf("%d",&T);
    while (T--) solve();
    return 0;
}

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 ("\n");
        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 ("\n");
    }
    return 0;
} 

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\n");
        else printf ("NO\n");
    }
    return 0;
}

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\n",ans);
}
int main () {
    solve();
    return 0;
}

原文地址:https://www.cnblogs.com/zhanglichen/p/12407535.html

时间: 2024-08-30 18:25:39

Codeforces补题2020.3.4 (Round620 Div2)的相关文章

Codeforces 补题记录

首先总结一下前段时间遇到过的一些有意思的题. Round #474 (Div. 1 + Div. 2, combined)   Problem G 其实关键就是n这个数在排列中的位置. 这样对于一个排列,设$f[pos] = p$, 那么从位置$1$到位置$pos$最大值被刷新了$a$次,从位置$n$到位置$pos$最大值被刷新了$b$次. 去掉$n$之后,剩下$n-1$个数被分成了两个部分. 假设把这$n-1$个数分成$a+b-2$个组,分配给左边$a-1$个组,给右边$b-1$个组. 对于$

codeforces补题:979

codeforces 979b::: 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+100; 4 int n; 5 char s[maxn]; 6 int num[100];//Kuro Shiro Katie 7 int ansl[5]; 8 9 int solve(){ 10 scanf("%s",s+1); 11 memset(num,0,sizeof(num)); 12 i

codeforces 984补题

codeforces 984a 1 #include<bits/stdc++.h> 2 using namespace std; 3 int n; 4 int num[1010]; 5 int main(){ 6 scanf("%d",&n); 7 for(int i=1;i<=n;i++) scanf("%d",&num[i]); 8 sort(num+1,num+n+1); 9 if(n%2==1) printf("%

Codeforces VP/补题小记 (持续填坑)

Codeforces VP/补题小记 1149 C. Tree Generator 给你一棵树的括号序列,每次交换两个括号,维护每次交换之后的直径. ? 考虑括号序列维护树的路径信息和,是将左括号看做 \(-1\) ,右括号看做 \(1\) ,那么一段竖直向上的路径可以表示为括号序列的一个区间和,一段竖直向下的路径可以看做括号序列的一个区间和的相反数.我们要维护的是树的直径,也就是一段连续的和减去紧随其后的一段连续的差.具体来说就是 \[ \max_{\forall [l,r]}\{\sum_{

Educational Codeforces Round 74 (Rated for Div. 2)补题

慢慢来. 题目册 题目 A B C D E F G 状态 √ √ √ √ × ? ? //√,×,? 想法 A. Prime Subtraction res tp A 题意:给定\(x,y(x>y)\),问能否将\(x-y\)拆成任意多个质数之和 1.任意大于\(1\)的整数\(k\)都可以用\(2\)与\(3\)的线性表示 证: 若\(k\)是偶数,显然: 若\(k\)是奇数,则\(k\)可以表示成\(k = 3 + 2*k'\),显然: 毕. #include<bits/stdc++.h&

Codeforces Round #634 (Div. 3) 补题

A. Candies and Two Sisters 签到题,直接输出即可 代码 #include<bits/stdc++.h> #define INF 0x3f3f3f3f typedef long long ll; using namespace std; inline void read(int &p) { p=0;int flag=1;char c=getchar(); while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();} w

4.30-5.1cf补题

//yy:拒绝转载!!! 悄悄告诉你,做题累了,去打两把斗地主就能恢复了喔~~~ //yy:可是我不会斗地主吖("'▽'") ~~~那就听两遍小苹果嘛~~~ 五一假期除了花时间建模,就抽空把最近没做的CF题补了点..毕竟明天开始又要继续上好多课呐...Yes, I can!(? •_•)?……(I can Huá shuǐ~~) codeforces 803 A. Maximal Binary Matrix   [简单构造] 题意:n行和n列填充零矩阵. 您要将k个1放在其中,使得得到

Codeforces gym Hello 2015 Div1 B and Div2 D

Codeforces gym 100571 problem D Problem 给一个有向图G<V,E>和源点S,边的属性有长度L和颜色C,即E=<L,C>.进行Q次询问,每次给定一个点X,输出S到X的最短路的长度(不存在则输出 -1).但要求S到X的路径中相邻两条边颜色不一样. Limits Time Limit(ms): 1000 Memory Limit(MB): 256 |V|, |E|: [1, 10^5] X, S: [1, |V| ] L: [1, 10^9] |C|

[2015hdu多校联赛补题]hdu5371 Hotaru&#39;s problem

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5371 题意:把一个数字串A翻过来(abc翻过来为cba)的操作为-A,我们称A-AA这样的串为N-sequence,现在给你一个数字串,问你这个串中最长的N-sequence子串长度 解:可以想到A-A是一个回文串,-AA也是一个回文串,那么首先Manacher跑一遍求出所有回文子串 可以想到任意两个互相覆盖的回文子串都可以表示成N-sequence 然后有三种搞法: 1.时间复杂度O(N*logN