Codeforces Round 885 (Div. 2)A-C题解
A:
题意:给你一个长度为n*m的商场,每一个商场都有它自己的坐标(x,y),1<=x<=n,1<=y<=m,
然后给你李华和她的几个朋友的坐标,在每一分钟后李华会去她相邻的商场,之后她的朋友也会去她相邻的商场(在已知李华去哪个商场之后),此时1分钟结束。现在李华的朋友要去寻找李华,李华很着急,问你现在她是否可以一直不被她的朋友找到(即在某一分钟后李华的坐标和她的其中一个朋友的坐标相同)。
思路:
首先,显而易见的,如果李华在角落,并且有个人(李华&friend)的坐标满足
|x李华-x李华&friend|+|y李华-y李华&friend|=1
那么李华接下来无论怎么走,李华friend都是可以直接抓到她的。
李华在角落,可以看做是在一条y=kx+b的一条直线上(k=1或者k=-1,其实都一样,就默认k为1)。李华的移动可以看做是这条直线k不变,b在不断变化。
那么李华friend也是在这一条直线上。那么我们可以发现,对于这两个人,无论李华怎么走,李华friend都是可以和李华保持都是在同一条直线上,并且在此基础之上李华friend会不断接近李华,直到把李华逼近到角落,此时李华一定会被抓住。
那么说了这么多,可以得到一条结论,对于李华所在的y=x+b这条直线上,如果有李华friend也在李华所在的这一条直线上,那么李华一定会被抓住。
那如果李华和李华friend不在同一条直线上呢
对于这种情况,我们假设某一个李华friend在直线y=x+b1,而李华在直线y=x+b2,首先李华向周围移动一格,那么k不变,b2也会+1或者-1。那对于李华friend,k也不发生变化,b1同样+1或者-1
1.如果b2+1并且b1+1或者b2-1并且b1-1,b1和b2的差不发生变化,两直线不会相同;
2.如果b1+1&&b2-1 或者 b1-1&&b2+1 ,那么b1和b2的差值会增加2或者减少2,那么如果当 abs(b1-b2)%2==0 的时候,无论李华怎么走,李华friend也可以在某一时刻走到与李华相同直线的时候。
那么对于李华和她的所有朋友,如果两者直线的b相差的绝对值%2==0,那么这个人一定
可以抓住李华,否则就一定抓不住。
代码:
void slove( )
{
int t,xx,yy;
cin>>n>>m>>t;
cin>>xx>>yy;
for(int i =1;i<=t;i++)
{
cin>>x[i]>>y[i];
}
for(int i =1;i<=t;i++)
{
if(abs(abs(yy-xx)-abs(y[i]-x[i]))%2==0){
cout<<"NO\n";
return ;
}
}
cout<<"YES\n";
return ;
}
B:
题意:有一条由n个木板组成的桥,每个目板都有自己的颜色,现在李华在第一块木板面前,她想只走一种颜色的木板,现在问你,在可以改变一块(或者0块)木板的颜色的情况下,李华只走一种颜色的木板,李华一次需要跨过的木板的最大值的最小是多少。
思路:
更新每种颜色的木板出现的下标,然后纪录最大的和次大的同种颜色的木板到上一个木板的距离。最后用n+1代表最后一块木板更新一遍。
之后对每个元素的最大值进行改变颜色的操作,max=max/2,和次大值取最大值。然后取每种颜色的最小值即可。
代码:
void slove( )
{
int t;
cin>>n>>m;
map<int,int>p; // 存当前元素的前一个出现的元素的下标
map<int,pair<int,int>>q; // 存当前元素的距离的最大值和次大值
for(int i =1;i<=n;i++) {
cin>>s[i];
if(!q[s[i]].first) q[s[i]].first=i-p[s[i]];//没有最大值
else {
int dis=i-p[s[i]];//当前元素与上一个元素的下标的差
if(!q[s[i]].second) {//没有次大值
q[s[i]].second=dis;
if(q[s[i]].second>q[s[i]].first)swap(q[s[i]].first,q[s[i]].second);// 转换最大值与次大值
}
else {//次大值和最大值都存在
if(dis>q[s[i]].first){//当前距离大于最大值,直接覆盖
q[s[i]].second=q[s[i]].first;
q[s[i]].first=dis;
}
else if(dis>q[s[i]].second)//如果只大于次大值
q[s[i]].second=dis;
}
}
p[s[i]]=i;//更新距离
}
for(auto i:p)//所有存在的颜色更新距离
{
int j=i.first,x=i.second;
// cout<<j<<" "<<q[j].first<<" "<<q[j].second<<endl;
if(!q[j].second)
{
q[j].second=n+1-x;
if(q[j].second>q[j].first)swap(q[j].first,q[j].second);
}
else{
int dis=n+1-x;
//cout<<dis<<endl;
if(dis>q[j].first){
q[j].second=q[j].first;
q[j].first=dis;
}
else if(dis>q[j].second)
q[j].second=dis;
//cout<<j<<" "<<q[j].first<<" "<<q[j].second<<endl;
}
}
int res=n/2;
for(auto i:q)
{
int j=i.first,ma=i.second.first-1,mi=i.second.second-1;
//cout<<j<<" "<<ma<<" "<<mi<<endl;
res=min(res,max(ma/2,mi));
}
cout<<res<<endl;
C:
题意:给你a,b两个数组,让你不断进行以下操作:
新建一个数组c,使ci=|ai-bi|,ai=bi,bi=ci.
问经过任意次后是否可以使 a 数组中的每个数全为0。
思路:
首先每组的ai,bi是独立的,那么我们可以考虑每组的(a,b)变成(0,x)的情况。
通过规律我们可以看出当已经是(0,x)这种情况下,之后的变化是
( 0 , x ) - > ( x , x ) - > ( x , 0 ) - > ( 0 , x ),那么就是每三次操作为一次循环,
I那么对于每组所需要的操作sI,只需要判断他们取模三是否一致即可。
有一种可以简化时间的方法:
当x>=2y时.他会进行三次操作
( x , y ) - > ( y , x - y ) - > ( x - y , x - 2y ) - > ( x - 2y , y ) ;那么我们可以使x对2y取余,这样不影响最后的答案,之后可以直接暴力算次数即可。
代码:
void slove( )
{
b[0]=b[1]=b[2]=0;
int t;
sc_int(n);
for(int i =1;i<=n;i++)cin>>a[i];
for(int i =1;i<=n;i++)
{
int x;
cin>>x;
if(x==0&&a[i]==0)continue;
if(x) a[i]%=2*x;
int time=0,k;
while(a[i])
{
k=abs(a[i]-x);
x=a[i];
a[i]=k;
if(x)a[i]%=2*x;
time++;
}
b[time%3]++;
}
int res=0;
if(b[0])res++;
if(b[1])res++;
if(b[2])res++;
if(res<=1)cout<<"YES\n";
else cout<<"NO\n";
// cout<<endl;
}