2018CCPC吉林赛区(重现赛)部分题解

前言

一个破计算器能搞出一堆幺蛾子,只能说博主就是个fw。
不管了,所有博主没法处理的就都是不合法操作。博主写了半天就只有一个东西是绝对没有bug的——遇到错误时的处理系统。
既然不想被人看到错误,那就干脆让别人一直都能看到你正确的那部分。

这套题的题目真的是让Jo厨狂喜啊,high到不行。


The Fool(规律)

比赛链接:https://acm.dingbacode.com/showproblem.php?pid=6555

题目大意

在这里插入图片描述
请求出 ∑ i N [ n i ] \sum_{i}^{N}[\frac{n}{i}] iN[in]的奇偶性,其中[x]为向下取整。

思路

伊奇真的好喜欢波波啊呜呜呜┭┮﹏┭┮

打表找规律,最后会发现这个值的奇偶性与其开方值的奇偶性相同。

AC代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e5+100;

int main()
{
    int t;
    int cnt=0;
    cin>>t;
    while(t--){
        cout<<"Case "<<(++cnt)<<": ";
        int n;
        cin>>n;
        n=int(sqrt(n));
        if(n&1) cout<<"odd"<<endl;
        else cout<<"even"<<endl;
    }
}

The World(思维)

比赛链接:https://acm.dingbacode.com/showproblem.php?pid=6556

题目大意

在这里插入图片描述

由于各地所属的时区不同,在旅游的过程中算出目的地的地方时显得尤为重要。

现给出四座城市的名称与其地方时的信息:

  • 北京(Beijing),中国首都,地方时为UTC(世界标准时间)+8;
  • 华盛顿(Washington),美国首都,地方时为UTC(世界标准时间)-5;
  • 伦敦(London),英国首都,地方时为UTC(世界标准时间);
  • 莫斯科(Moscow),俄罗斯首都,地方时为UTC(世界标准时间)+3;

接下来会给出一个时间:XX:XX AM/PM,紧接着给出两个城市的名称A、B。
如果A城市的地方时为XX:XX AM/PM,请问:

城市B的地方时是多少?
城市B相对于城市A是昨天(Yesterday)/今天(Today)/(明天)Tomorrow?

按格式输出"Yesterday/Today/Tomorrow hour:minute AM/PM"。

思路

塑料的『The World』,铁打的『Lovers』。

很简单的一道题,先把A的地方时换算成世界标准时间,然后再换算成B的地方时,中间过程记录是哪一天即可。
不过这题还是挺坑的,它的时间是这样的:
在这里插入图片描述
注意一下即可。

AC代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
map<string,int> mp;

void init()
{
    mp.clear();
    mp["Beijing"]=8;
    mp["Washington"]=-5;
    mp["Moscow"]=3;
    mp["London"]=0;
}

int main()
{
    int t;
    init();
    int cnt=0;
    cin>>t;
    while(t--){
        string time,noon;
        string p1,p2;
        cin>>time>>noon;
        cin>>p1>>p2;
        int flag=0,h=0,pos=0;
        for(;;pos++){
            if(time[pos]==':') break;
            h=h*10+time[pos]-'0';
        }
        if(noon=="PM"&&h!=12) h+=12;
        if(noon=="AM"&&h==12) h=0;

        h=h-mp[p1]+mp[p2];

        if(h<0){
            flag=-1;
            h=24+h;
        }

        else if(h>=24){
            flag=1;
            h=h-24;
        }

        if(h==0) h=12,noon="AM";
        else if(h<=11) noon="AM";
        else if(h==12) noon="PM";
        else h-=12,noon="PM";

        cout<<"Case "<<(++cnt)<<": ";
        if(flag==-1) cout<<"Yesterday ";
        else if(flag==1) cout<<"Tomorrow ";
        else cout<<"Today ";
        cout<<h<<time.substr(pos)<<" "<<noon<<endl;
    }
}

The Tower(计算几何)

比赛链接:https://acm.dingbacode.com/showproblem.php?pid=6559

题目大意

在这里插入图片描述
在三维坐标轴上存在一个圆锥。底部圆的圆心为 ( 0 , 0 , 0 ) (0,0,0) (000),半径为 r r r,圆锥高为 h h h
现在有一个处于 ( x 0 , y 0 , z 0 ) (x_0,y_0,z_0) (x0y0z0)的点以 ( v x , v y , v z ) (v_x,v_y,v_z) (vxvyvz)的速度运动着。
请问这个点什么时候会撞到圆锥,输出碰撞时间。

思路

最近对这种几何题尤其的上瘾,所以当我看完题目之后整个人都是赛高泥high铁鸭子哒(bushi)。
在这里插入图片描述
首先我们假设点 ( x 0 , y 0 , z 0 ) (x_0,y_0,z_0) (x0y0z0)与圆锥相撞于点 ( x , y , z ) (x,y,z) (xyz),那么就有: { x = x 0 + v x t y = y 0 + v y t z = z 0 + v z t \left\{\begin{matrix} x=x_0+v_xt\\ y=y_0+v_yt\\ z=z_0+v_zt\\ \end{matrix}\right. x=x0+vxty=y0+vytz=z0+vzt
接下来取圆锥的纵截面:

在这里插入图片描述
由图可知(相似三角形): x 2 + z 2 r = x 2 + y 2 + ( z − h ) 2 r 2 + h 2 \frac{\sqrt{x^2+z^2}}{r}=\frac{\sqrt{x^2+y^2+(z-h)^2}}{\sqrt{r^2+h^2}} rx2+z2 =r2+h2 x2+y2+(zh)2
等式两边同时平方: x 2 + z 2 r 2 = x 2 + y 2 + ( z − h ) 2 r 2 + h 2 \frac{x^2+z^2}{r^2}=\frac{x^2+y^2+(z-h)^2}{r^2+h^2} r2x2+z2=r2+h2x2+y2+(zh)2

联立方程组得:
{ x = x 0 + v x t y = y 0 + v y t z = z 0 + v z t x 2 + z 2 r 2 = x 2 + y 2 + ( z − h ) 2 r 2 + h 2 \left\{\begin{matrix} x=x_0+v_xt\\ y=y_0+v_yt\\ z=z_0+v_zt\\ \frac{x^2+z^2}{r^2}=\frac{x^2+y^2+(z-h)^2}{r^2+h^2}\\ \end{matrix}\right. x=x0+vxty=y0+vytz=z0+vztr2x2+z2=r2+h2x2+y2+(zh)2

所有的字母中只有 t t t是未知量,接下来我们就需要开始苦逼的化简过程了。

在博主薅了 20 20 20分钟头发(也许不是头发)之后终于给它化简出来了:
[ h 2 ( v x + v y ) 2 − r 2 v z 2 − 2 h 2 v x v y ] t 2 [h^2(v_x+v_y)^2-r^2v_z^2-2h^2v_xv_y]t^2 [h2(vx+vy)2r2vz22h2vxvy]t2 + + + [ 2 h 2 ( v x + v y ) ( x 0 + y 0 ) − 2 r 2 v z ( z 0 − h ) − ( 2 h 2 x 0 v y + 2 h 2 y 0 v x ) ] t [2h^2(v_x+v_y)(x_0+y_0)-2r^2v_z(z_0-h)-(2h^2x_0v_y+2h^2y_0v_x)]t [2h2(vx+vy)(x0+y0)2r2vz(z0h)(2h2x0vy+2h2y0vx)]t + + + [ h 2 ( x 0 + y 0 ) 2 − r 2 ( z 0 − h ) 2 − 2 h 2 x 0 y 0 ] [h^2(x_0+y_0)^2-r^2(z_0-h)^2-2h^2x_0y_0] [h2(x0+y0)2r2(z0h)22h2x0y0] = = 0 ==0 ==0
(这要是没求对估摸着我当时就直接脑溢血爬不出机房了)

这就变成了一个简 单的一元二次方程式了: { a = h 2 ( v x + v y ) 2 − r 2 v z 2 − 2 h 2 v x v y b = 2 h 2 ( v x + v y ) ( x 0 + y 0 ) − 2 r 2 v z ( z 0 − h ) − ( 2 h 2 x 0 v y + 2 h 2 y 0 v x ) c = h 2 ( x 0 + y 0 ) 2 − r 2 ( z 0 − h ) 2 − 2 h 2 x 0 y 0 \left\{\begin{matrix} a=h^2(v_x+v_y)^2-r^2v_z^2-2h^2v_xv_y\\ b=2h^2(v_x+v_y)(x_0+y_0)-2r^2v_z(z_0-h)-(2h^2x_0v_y+2h^2y_0v_x)\\ c=h^2(x_0+y_0)^2-r^2(z_0-h)^2-2h^2x_0y_0\\ \end{matrix}\right. a=h2(vx+vy)2r2vz22h2vxvyb=2h2(vx+vy)(x0+y0)2r2vz(z0h)(2h2x0vy+2h2y0vx)c=h2(x0+y0)2r2(z0h)22h2x0y0

这样就可以求出两个 t t t值,接下来只需要判断 t t t值是否合理,合理的话取最小值即可。

AC代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
double r,h,x,y,z,vx,vy,vz;
bool judge(double t)
{
    double x_z=x+t*vx;
    double y_z=y+t*vy;
    double z_z=z+t*vz;
    if(z_z>=0&&z_z<=h&&x_z*x_z+y_z*y_z<=r*r)
        return true;
    else return false;
}
int main()
{
    int t,cnt=0;
    scanf("%d",&t);
    while(t--){
        //11
        scanf("%lf%lf",&r,&h);
        scanf("%lf%lf%lf%lf%lf%lf",&x,&y,&z,&vx,&vy,&vz);
        double a,b,c;
        a=h*h*(vx+vy)*(vx+vy)-r*r*vz*vz-2*h*h*vx*vy;
        b=2*h*h*(vx+vy)*(x+y)-2*r*r*vz*(z-h)-(2*h*h*x*vy+2*h*h*y*vx);
        c=h*h*(x+y)*(x+y)-r*r*(z-h)*(z-h)-2*h*h*x*y;
        double t1=(-b+sqrt(b*b-4*a*c))/(2.0*a);
        double t2=(-b-sqrt(b*b-4*a*c))/(2.0*a);
        double ans=inf;
        if(judge(t1)) ans=min(ans,t1);
        if(judge(t2)) ans=min(ans,t2);
        printf("Case %d: %.10f\n",++cnt,ans);
    }
}

几何题做起来是真的太上头了。


Strength(贪心)

比赛链接:https://acm.dingbacode.com/showproblem.php?pid=6563

题目大意

(找了半天没找到色猩猩对应的那一帧,就乎着看吧)

在这里插入图片描述
现在 A l i c e Alice Alice n n n个小兵,每个小兵的攻击力为 a i a_i ai
B o b Bob Bob m m m个小兵,每个小兵的攻击力为 b i b_i bi

A A A小兵(攻击力为 x x x)进攻 B B B小兵(攻击力为 y y y)的时候会出现以下情况:

  1. B B B小兵处于防御姿态, x < y x<y x<y。 => A A A小兵死亡, B B B小兵毫发无伤;
  2. B B B小兵处于防御姿态, x > = y x>=y x>=y。 => A A A小兵死亡,B小兵死亡;
  3. B B B小兵处于进攻姿态, x < y x<y x<y。=> A A A小兵死亡, B B B小兵毫发无伤, A A A小兵的主人受到 y − x y-x yx点伤害;
  4. B B B小兵处于进攻姿态, x > = y x>=y x>=y。=> A A A小兵死亡, B B B小兵死亡, B B B小兵的主人受到 x − y x-y xy点伤害;

一旦主人没有小兵可以用的时候,对方接下来的进攻都会直接对主人造成伤害。
一开始所有的小兵都是进攻姿态。

接下来是 A l i c e Alice Alice的进攻时间, B o b Bob Bob把他手下的一部分小兵改为防御姿态。
请问 A l i c e Alice Alice最多可以对 B o b Bob Bob造成多少伤害?

思路

贪心,分情况讨论。

一.只揍Bob的进攻姿态小兵。

如果我们打防御姿态的小兵,就算打赢了,也不会对 B o b Bob Bob造成伤害,还会废掉我们的一个小兵,不是很划得来。
所以我们把主力全部用在打 B o b Bob Bob的进攻姿态小兵上面,贪出最大伤害值。

二.杀掉Bob所有的兵。

如果我们有能力把Bob的兵全部干掉,这样我们剩下的兵就可以造成真实伤害,是有可能造成一个很高的伤害值的。
这样的话我们就要考虑如何处理Bob的防御兵了。我们要尽可能地用和其防御兵攻击力差不多的兵来完成自爆行动,这样的话最佳的处理方式就是lower_bound
但一个兵只能用一次,所以还要记录一下自己哪些兵是在清理Bob所有的兵时所用的。

AC代码

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
struct node
{
    int x,y;
}b[maxn];

int a[maxn];
bool vis[maxn];

bool cmp(node z,node c)
{
    if(z.y!=c.y)
        return z.y<c.y;
    else
        return z.x<c.x;
}

int main()
{
    int t,cnt=0;
    cin>>t;
    while(t--){
        int n,m;
        cin>>n>>m;
        for(int i=1;i<=n;i++)
            cin>>a[i],vis[i]=false;
        for(int i=1;i<=m;i++)
            cin>>b[i].x;
        for(int i=1;i<=m;i++)
            cin>>b[i].y;
        sort(a+1,a+1+n);
        sort(b+1,b+1+m,cmp);
        int maxx=-inf;
        int ans=0;
        int pos1=n,pos2=1;
        while(b[pos2].y==0) pos2++;
        pos2--;
        while(pos1&&pos2){
            if(a[pos1]>b[pos2].x)
                ans+=a[pos1]-b[pos2].x;
            else
                break;
            pos1--,pos2--;
        }
        maxx=max(ans,maxx);
        ans=0;
        pos1=n,pos2=m;
        int flag=1;
        while(b[pos2].y==1){
            int pos=lower_bound(a+1,a+1+n,b[pos2].x)-a;
            while(vis[pos]&&pos<=n) pos++;
            if(pos==n+1){
                flag=0;
                break;
            }
            vis[pos]=true;
            pos2--;
        }
        if(flag){
            while(pos1&&pos2){
                if(vis[pos1]){
                    pos1--;
                    continue;
                }
                if(a[pos1]>b[pos2].x) //这里还是可以贪伤害的
                    ans+=a[pos1]-b[pos2].x,pos1--,pos2--;

                else{
                    flag=0;
                    break;
                }
            }
            if(flag){
                while(pos1){
                    if(vis[pos1]){
                        pos1--;
                        continue;
                    }
                    ans+=a[pos1];
                    pos1--;
                }
            }
            maxx=max(maxx,ans);
        }
        cout<<"Case "<<(++cnt)<<": "<<maxx<<endl;
    }
}

后话

感谢阅读,希望能对你产生一点用处。

以下台词取自《银魂:完结篇·永远的万事屋》:
(每次看这一段的时候都会疯狂的起鸡皮疙瘩+落泪,真的是太燃了,配合着『現状ディストラクション』的BGM)
(SPYAIR,yyds!)

在这里插入图片描述

"银时啊"
"我们曾经失去过很多朋友"
"一次次地被打击"
"我以为我们再也回不到那段时光了"
"而你...我们..."
"到头来还是一起回到了这个地方啊"
"银时!"
"你们前进的道路,就由我们来开拓!"
"所以现在既不是为了未来"
"也不是为了过去"
"而是为了我们所活的当下啊!"
"去开辟吧!"

吾日三省吾身:日更否?刷题否?快乐否?
更新了,但不是日更;已刷;激动
路漫漫其修远兮,吾将上下而求索

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值