【Codeforces】Codeforces Round #551 (Div. 2) 解题报告

Posted on 2019-04-15 20:58  opethrax  阅读(197)  评论(0编辑  收藏  举报

比赛链接

这一个月有点松弛了,吃了好多亏。这一个月来打的第一场CF就当成是停止放松的开始吧。

在写A的时候用到了一个叫做fst的变量,于是...但是还是涨了一点点分(我上次是多惨啊)。

不敢tui不敢tui...自闭+自卑了。

 

A. Serval and Bus


 

题目大意:一个傻憨憨t时到车站,见车就坐,给出每辆公交车首班车到达时间及之后的时间间隔,求傻憨憨最后上的是哪一辆车。

数据范围:≤ 𝑛 ≤ 100 , 1 ≤ n ≤ 100 , ≤ t ≤ 105 , ≤ si,di ≤ 105

无代码

 

B. Serval and Toy Bricks
 
 
题目大意:有一堆积木,占了n×m的地方,告诉你从侧视图(正?),以及那些位置上有积木,求一种可行方案。

数据范围:1𝑛,𝑚,100

无代码

 
C. Serval and Parenthesis Sequence
 

题目大意:有一个括号序列,要求它本身合法且它的所有前缀都严格不合法,现在有一些位置不确定,求一种合法方案,否则输出 " :( " (我跟你讲我现在就这个表情)

数据范围:≤ |s| ≤ 105

先判无解,再贪心,尽可能先放做括号 "(" 这样前缀就不容易出现合法的,最后再判下合法就可以了。

无代码

 
D. Serval and Rooted Tree
 
题目大意:给出一棵根节点是1的树,现在需要在k个叶节点上放了1~k这些数作为权值,除叶节点外每个节点都会从其所有儿子里取min or max权值,求根节点权值的最大值
数据范围:2𝑛3*105

对于min节点来说,如果有x个儿子,那么就只能取到第x小的元素,取不到前dp[i]个。令dp[i]表示i的儿子中取不到前dp[i]个,min节点取它儿子dp的和,max节点取它儿子dp的最小值,答案为k-dp[1]+1

代码:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 #include<vector>
 5 using namespace std;
 6 
 7 template<class T>void read(T &x){
 8     x=0; bool f=0; char c=getchar();
 9     while(c<'0'||'9'<c){f|=(c=='-'); c=getchar();}
10     while('0'<=c&&c<='9'){x=(x<<1)+(x<<3)+(c^48); c=getchar();}
11     x=f?-x:x;
12 }
13 
14 const int N=300050;
15 const int inf=N;
16 int n,k;
17 int a[N],fa[N],dp[N];
18 vector<int>son[N];
19 
20 void dfs(int x){
21     if(son[x].size()==0){dp[x]=1; ++k; return ;}
22     a[x]?dp[x]=inf:dp[x]=0;
23     for(int i=son[x].size()-1,y;~i;--i){
24         y=son[x][i];
25         dfs(y);
26         a[x]?dp[x]=min(dp[x],dp[y]):dp[x]+=dp[y];
27     }
28 }
29 int main(){
30     read(n);
31     for(int i=1;i<=n;++i)read(a[i]);
32     for(int i=2;i<=n;++i)read(fa[i]), son[fa[i]].push_back(i);
33     dfs(1);
34     printf("%d",k-dp[1]+1);
35     return 0;
36 }

 

E. Serval and Snake
 

数据范围:
(交互! 贯彻了交互题都是水题但是像我这样的傻憨憨不看的精神???)在一个n×n的网格里有一条蛇,我们向交互库查询它的一个子网格,并且告诉你蛇的身体经过这个子网格边界的次数(交点)。请在2019次查询内找到蛇头和蛇尾的位置(不需要区分头尾)。

数据范围:2𝑛≤1000

仔细想想我们发现在一个网格图中如果不包含蛇的头或尾是蛇的身体的一部分,就是一进一出,一进一出,一进一出...交点个数是偶数。反之就必然有头或尾在网格中。

我们先询问所有行和列(2*n次询问至多2000次),一定得到至少两行或者两列是奇数:头和尾在这两行或列中。

如果只有两行或者两列是奇数,那么蛇头蛇尾在同一行或者列中,用剩下的次数二分这行(列)的位置。

否则就是在不同的行列中,查询一次就可以确定两个点的位置。

代码:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 inline int read(){
 7     int x=0; char c=getchar();
 8     while(c<'0'||'9'<c)c=getchar();
 9     while('0'<=c&&c<='9'){x=(x<<3)+(x<<1)+(c^48); c=getchar();}
10     return x;
11 }
12 
13 int n;
14 int h[3],p[3];
15 int a,b;
16 
17 int ask(int a,int b,int c,int d){
18     fflush(stdout);
19     printf("? %d %d %d %d\n",a,b,c,d);
20     fflush(stdout);
21     return read()&1;
22 }
23 
24 int main(){
25     n=read();
26     for(int i=1;i<=n;++i){
27         if(ask(i,1,i,n))h[++a]=i;
28         if(a>=2)break;
29     }
30     for(int i=1;i<=n;++i){
31         if(ask(1,i,n,i))p[++b]=i;
32         if(b>=2)break;
33     }
34     if(a&&b){
35         if(ask(h[1],p[1],h[1],p[1]))printf("! %d %d %d %d\n",h[1],p[1],h[2],p[2]);
36         else printf("! %d %d %d %d\n",h[1],p[2],h[2],p[1]);
37         return 0;
38     }
39     if(!a){
40         int l=1,r=n,mid,ans;
41         while(l<=r){
42             mid=(l+r)>>1;
43             if(ask(1,p[1],mid,p[1])){
44                 ans=mid;
45                 r=mid-1;
46             }
47             else l=mid+1;
48         }
49         printf("! %d %d %d %d\n",ans,p[1],ans,p[2]);
50         return 0;
51     }
52     if(!b){
53         int l=1,r=n,mid,ans;
54         while(l<=r){
55             mid=(l+r)>>1;
56             if(ask(h[1],1,h[1],mid)){
57                 ans=mid;
58                 r=mid-1;
59             }
60             else l=mid+1;
61         }
62         printf("! %d %d %d %d\n",h[1],ans,h[2],ans);
63         return 0;
64     }
65 }

 

F. Serval and Bonus Problem
 
题目大意:还没看懂...
数据范围:
科技点不足。坑待填。