Codeforces Round #516 (Div.2) A-E 题解


令我非常膜拜出题人的一场div.2,D题不愧为神题,这题不去做一下不是好汉.

图片欣赏

在这里插入图片描述
机房里一半都挂了D题.果然我还是最菜了.

过程

先迅速A掉AB两题,看看C题,暂时不会,跳D题,发现D题是个sb搜索题,10分钟写出来竟然 p p pp pp了,然后我成为了全场第二个ppD题的人.
接下来想想C题,发现C题果然是个sb题,迅速通过.
然后去研究E题,并用二分通过.
接下来我不禁开始思考D题有没有什么锅.
最后两分钟我发现直接bfs搜到的不一定最优,这时已经来不及了.
热烈祝贺一波 _ _ 123456 _ _ \_\_123456\_\_ __123456__倒一!

A

把三个数排序一下,看看较小两个数加起来和大的数相差多少和 0 0 0取个 max ⁡ \max max即可.

B

a − b = a   x o r   b , b ∈ a a-b=a\ xor \ b,b\in a ab=a xor b,ba.
答案即为 1 &lt; &lt; p o p c o u n t ( x ) 1&lt;&lt;popcount(x) 1<<popcount(x)也即 2 x 的 二 进 制 中 1 的 个 数 2^{x的二进制中1的个数} 2x1.

C

大胆猜想,小心求证.
可以发现将相同的字母堆在一起显然不会使回文串的个数减少,因此只要直接对原字符串排序即可.

D

用普通bfs会GG.
那么如何保证延伸的时候一定会延伸到最优的结果呢?
我们用双端队列来处理bfs.
当上下移动的时候我们就把这个 n o d e node node放到队头,否则放到队尾.
这样就可过了.

#include<bits/stdc++.h> //lthea Myse Valgulious
using namespace std;
const int aoi=2018,d[]={1,0,-1,0,0,1,0,-1};
char mp[aoi][aoi];
int n,m,r,c,lx,ly,vis[aoi][aoi];

struct node{
int x,y,lt,rt;
};

void bfs(int sx,int sy){
deque<node> q;
q.push_back(node{sx,sy,0,0});
vis[sx][sy]=1;
for (;!q.empty();){
  node u=q.front(); q.pop_front();
  for (int i=0;i<4;++i){
    int nx=u.x+d[i],ny=u.y+d[i+4];
    int nlt=u.lt+(i==3),nrt=u.rt+(i==1);
    if (nx>0&&nx<=n&&ny>0&&ny<=m&&mp[nx][ny]^'*'&&nlt<=lx&&nrt<=ly&&!vis[nx][ny]){
      vis[nx][ny]=1;
      if (i&1) q.push_back(node{nx,ny,nlt,nrt});
      else q.push_front(node{nx,ny,nlt,nrt});
      }
    }
  }
}

int main(){
int i,j,llx=0;
n=read(),m=read();
r=read(),c=read();
lx=read(),ly=read();
for (i=1;i<=n;++i) scanf("%s",mp[i]+1);
bfs(r,c);
for (i=1;i<=n;++i) 
  for (j=1;j<=m;++j) llx+=vis[i][j];
write(llx);
}

E

二分.
首先我们把一半的点放在直线 y = 1 y=1 y=1上,每次取中间点,给黑色往左,白色往右.
一半点给完之后确定黑白分界线的一个端点.
然后把剩下一半点放在直线 x = 1 x=1 x=1上,用同样的方式操作.
最后将确定好的直线的两个端点输出.

#include<bits/stdc++.h> //lthea Myse Valgulious
using namespace std;
const int mulu=1e9;
int main(){
int i,j,n=read();
if (n==1){
  cout<<"1 1"<<endl;
  cout<<"3 3 6 3"<<endl;
  return 0;
  }
ll l=1,r=mulu-1;
for (i=1;i<=(n>>1);++i){
  ll mid=(l+r)>>1;
  cout<<mid<<" "<<1<<endl;
  string s; cin>>s;
  s.front()=='b'?r=mid-1:l=mid+1;
  }
ll t=l+1;
l=1,r=mulu-1;
for (n-=n/2,i=1;i<=n;++i){
  ll mid=l+r>>1;
  cout<<1<<" "<<mid<<endl;
  string s; cin>>s;
  s.front()=='b'?r=mid-1:l=mid+1;
  }
printf("%lld %lld %lld %lld\n",1ll,l+1,t,1ll);
fflush(stdout);
}

谢谢大家.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值