B题题解来说是道贪心,但我不知道为什么像题解那样贪心,有知道的大佬可以说一说。。。
F题是道比较直观的平面几何题。因为小球直径是r所以将矩形各个边向中间缩小r形成一个小矩形,如果圆心可能落在小矩形上(包括边界)那么输出yes,否则no。这就是先对于矩形的处理。
对于这道题有两种判断方法来确定小球是否能落在小矩形内
第一种就是比较板子的,判断圆心移动路径(为射线)与矩形的边(或者对角线)是否有交点,这种方法我不太会。。。就在这里没有写,大家可以看看cf大佬写的代码。
第二种比较傻的方法,就是判断小球的圆心到达小矩形的左边的情况下,计算对应的时间,以此计算y的位置,判断y是否合法,合法的话输出yes;
然后再判断小球的圆心到达小矩形的右边情况下,计算对应的时间,以此计算y的位置,判断y是否合法,合法的话输出yes;
然后再判断小球的圆心到达小矩形的下边的情况下,计算对应的时间,以此计算x的位置,判断是否合法,合法的话输出yes;
最后判断小球的圆心到达小矩形的上边的情况下,计算对应的时间,以此计算x的位置,判断是否合法,合法的话输出yes;
如果上述情况都不成立的话输出no。
这种方法的坑点(卡了我一天。。。)就是需要注意圆心是否朝小矩形的各个边移动,这点必须要判断,不能忽视,我是看了大佬的代码才注意到的。。。具体可以看我的判断条件。
还有就是小矩形可能根本不存在,这是样例2,需要判断一下。
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
void slove(){
ll x, y, r, vx, vy, lx, ly, rx, ry;
double time;
scanf("%lld %lld %lld %lld %lld", &x, &y, &r, &vx, &vy);
scanf("%lld %lld %lld %lld", &lx, &ly, &rx, &ry);
lx += r, ly += r, rx -= r, ry -= r;
if(lx <= rx && ly <= ry){
if(x >= lx && x <= rx){
if(y >= ly && y <= ry){
printf("Yes\n");
return ;
}
}
if(vx != 0){
double xx, yy;
if((x <= lx && vx > 0) || (x >= lx && vx < 0)){
time = (double)(lx - x) / vx;
yy = y + vy * time;
if((lx - x) * vx >= 0 && yy <= ry && yy >= ly){
printf("Yes\n");
return ;
}
}
if((x <= rx && vx > 0) || (x >= rx && vx < 0)){
time = (double)(rx - x) / vx;
yy = y + vy * time;
if((rx - x) * vx >= 0 && yy <= ry && yy >= ly){
printf("Yes\n");
return ;
}
}
}
if(vy != 0){
double xx, yy;
if((y <= ly && vy > 0) || (y >= ly && vy < 0)){
time = (double)(ly - y) / vy;
xx = x + vx * time;
if((ly - y) * vy >= 0 && xx <= rx && xx >= lx){
printf("Yes\n");
return ;
}
}
if((y <= ry && vy > 0) || (y >= ry && vy < 0)){
time = (double)(ry - y) / vy;
xx = x + vx * time;
if((ry - y) * vy >= 0 && xx <= rx && xx >= lx){
printf("Yes\n");
return ;
}
}
}
}
printf("No\n");
return ;
}
int main(){
ll t;
scanf("%lld", &t);
while(t--){
slove();
}
return 0;
}
大佬的代码写的太牛了,思想都差不多,我就一起粘再这里了(卡的点也是看大佬代码才知道的。。。)
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,rx,ry,r,vx,vy,a,b,c,d;
signed main()
{
cin>>t;
while(t--)
{
cin>>rx>>ry>>r>>vx>>vy>>a>>b>>c>>d;
a+=r,b+=r,c-=r,d-=r;
int flag=0;
if(a<=c && b<=d)
{
double s1=(double)(a-rx)*vy/vx,s2=(double)(c-rx)*vy/vx;
double s3=(double)(b-ry)*vx/vy,s4=(double)(d-ry)*vx/vy;
if((a-rx)*vx>=0 && ry+s1>=b && ry+s1<=d)flag=1;
if((c-rx)*vx>=0 && ry+s2>=b && ry+s2<=d)flag=1;
if((b-ry)*vy>=0 && rx+s3>=a && rx+s3<=c)flag=1;
if((d-ry)*vy>=0 && rx+s4>=a && rx+s4<=c)flag=1;
}
if(flag)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}
有时间要看看平面几何了,感觉题比较直观,但写起来会出现小错,很隐蔽的小错,其实我也写了一版第一种方法的代码,但一直wa3,就是不知道哪里错了
一道博弈题,打表发现规律:
石子数 | 1 | 2 | 3 | 4 | 5 | 6 |
GG输赢 | win | win | lose | win | win | lose |
所以GG的输赢和n%3有关,对于赢的人获得的石子数,题目说明两人都会尽可能获得更多的石子,所以当n处于3的倍数时,YY会赢,但GG每次都会拿尽可能多的石子(即2个石子),为了保证赢的状态,YY每次只会拿一个石子,所以YY拿的石子数为n/3,当n%3!=0时,GG先拿1或2个石子使石子数到达必输态来交给YY处理,YY会拿尽可能多的石子(即2个石子)(这种情况就像是n为3的倍数一样),那么GG每次就只能拿一个石子,这样的话GG拿的石子总数就是n/3 + n%3
#include<bits/stdc++.h>
#define ll long long
#define inf 1e9
using namespace std;
void slove(){
ll n;
cin >> n;
if(n % 3){
cout << 0 << " " << n / 3 + n % 3 << endl;
}
else{
cout << 1 << " " << n / 3 << endl;
}
}
int main(){
ll t;
cin >> t;
while(t--){
slove();
}
return 0;
}