2018CCPC吉林站(部分题解)

目录

HDU 6559 The Tower(解析几何)

HDU 6560 F.The Hermit(思维:数学不等式判结论)

HDU 6557 Justice(小根堆+并查集)


HDU 6559 The Tower(解析几何)

题意:

给出一个圆锥,底面圆心在原点(0,0,0),给出圆锥外一点(x0,y0,z0)(保证为圆锥外一点),以及该点在各个方向上的移动速度(vx,vy,vz)。求该点撞击在圆锥面上时的时间t。

 

思路:

假设撞击到圆锥上的点是A(x,y,z)。圆锥得横截面都是圆,都满足x^{2}+y^{2}=r^{2}

 平面图:

 由相似三角形得:\frac{​{r}'}{r}=\frac{h-z}{h},即{r}'=\frac{r(h-z)}{h}

假设撞击时间为t,则撞击点A的坐标是(x0+vxt,y0+vyt,z0+vzt)。

将A点代入圆的方程:(x_{0}+v_{x}*t)^{2}+(y_{0}+v_{y}*t)^{2}=\frac{r^{2}(h-(z_{0}+v_{0}t))^{2}}{h^{2}}

化简过程:

能先算的先算出来:k=r*r/(h*h)a=h-z0

平方展开,提取公因子t^{2}t,剩下部分是常数,每一部分的系数分别是aa,bb,cc。

三个系数的计算方法:

aa=vx*vx+vy*vy-k*vz*vz;
bb=2*x0*vx+2*y0*vy+2*k*a*vz;
cc=x0*x0+y0*y0-k*a*a;

经过化简得到一个一元二次方程:aa*t^{2}+bb*t+cc=0

求解t:t=\frac{-bb\pm sqrt(bb^{2}-4*aa*cc)}{2aa}

得到两个值t1,t2,设t1<t2:题目保证撞击点存在,并且撞击点的高z\epsilon [0,h],所以如果0\leqslant z_{0}+v_{z}*t1\leq h,则输出t1,否则输出t2。(如果t1<0,说明是和题目图底对底的圆锥,此时t2一定大于0,符合要求,因为保证有界)

 

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int t,cnt=1;
    scanf("%d",&t);
    while(t--)
    {
        double r,h,x0,y0,z0,vx,vy,vz,x,y,z;
        scanf("%lf%lf",&r,&h);
        scanf("%lf%lf%lf",&x0,&y0,&z0);
        scanf("%lf%lf%lf",&vx,&vy,&vz);
        double k=r*r/(h*h);
        double a=h-z0;
        double aa,bb,cc;
        aa=vx*vx+vy*vy-k*vz*vz;
        bb=2*x0*vx+2*y0*vy+2*k*a*vz;
        cc=x0*x0+y0*y0-k*a*a;
        double x1=(-bb+sqrt(bb*bb-4*aa*cc))/(2*aa);
        double x2=(-bb-sqrt(bb*bb-4*aa*cc))/(2*aa);
        if(x1>x2)
            swap(x1,x2);
        printf("Case %d: ",cnt++);
        if(x1<0)
            printf("%.10f\n",x2);
        else
        {
             double z1=z0+vz*x1;
             if(z1<0 || z1>h) 
                printf("%.10f\n",x2);
            else 
                printf("%.10f\n",x1);
        } 
    }
}

HDU 6560 F.The Hermit(思维:数学不等式判结论)

题意:

数字轴上有N个无线电台,第i个电台位于xi=i。第i站的广播范围为radi,即在[i - rad_{i} + 1, i + rad_{i} - 1]区间内的电台可以接收到第i站的信号。由于某种未知的原因,能够接收到第i站信号的左边界是非递减的,即i- rad_{i} +1\leq i +1 - rad_{i+1} +1

如果电台K同时满足以下两个条件,该电台就可以接收到i台的完美信号:

(1)k<i并且i-radi+1<=k(k在i的左边且在i范围内)

(2)存在另一站j(k\leq j < i),使得k和i都能接收到j站的信号,且k和j站之间的距离大于或等于j站和i之间的距离。

求每个i站,有多少站可以收到i站的完美信号,输出它们的异或和。

思路:

根据题意总结条件(k,j,i 三个电台之间关系):

(1)k\leq j < i

(2)k \geq i - rad[i] + 1 \geq 1

(3)k \geq j - rad[j] + 1 \geq 1

(4)i \leq j + rad[j] -1

(5)j - k \geq i - j \geq 1

 (6)i- rad_{i} +1\leq i +1 - rad_{i+1} +1

由(1)(6)可知:(3)在(2)的情况下显然成立,因此可删去(3)。
由(5)可知:(4)在(3)的情况下显然成立,因此可删去(4)。

最后留下的就只有(1),(2),(5),(6)。

(1)k\leq j < i

(2)k \geq i - rad[i] + 1 \geq 1

(5)j - k \geq i - j \geq 1

  (6) i- rad_{i} +1\leq i +1 - rad_{i+1} +1

总结K电台的范围:

(1)k \geq i - rad[i] + 1 \geq 1

(2)k\leq j < i

(3)k \leq 2 * j - i \leq 2 * ( i - 1 ) - i = i - 2(解不等式(5)得)

(4)因为 j < i,所以 j >= 2*j - i。

所以k得范围是【i-rad[i]+1,i-2】,每个i站,有i-2-(i-rad[i]+1)+1\Leftrightarrow rad[i]-2站可以收到i站的完美信号。(对于小于0得当0处理即可)。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000005;
int a[maxn];
int main()
{
    int t,cnt=1,n;
	cin>>t;
	while(t--)
    {
		cin>>n;
		for(int i=1;i<=n;i++)
		    cin>>a[i];
		int ans=0;
		for(int i=3;i<=n;i++)
			ans^=max(a[i]-2,0);
       cout<<"Case "<<cnt++<<": "<<ans<<endl;
	}
}

HDU 6557 Justice(小根堆+并查集)

题意:有n个砝码,每个砝码有一个权值k_{i},表示重量为\frac{1}{2^{k_{i}}},判断是否有可能将砝码分为两组,满足每组的重量都大于等于\frac{1}{2}。如果有则输出方案(0表示在第0组,1表示在第1组)。

思路:建立一个小根堆,将k_{i}都放进去。每次去最小值和次小值,k_{i}越小,\frac{1}{2^{k_{i}}}就越大,如果最小值和次小值相等,则\frac{1}{2^{k_{i}}}*2=\frac{1}{2^{k_{i}-1}},将ki-1在放入队列,这两个是一组;不相等时将最小值抛弃。如果最后有至少两个1/2则成立。并查集用来记录分组情况,最小值和次小值相等时,将次小值并到最小值上,最后父亲一样的是一组,独立的是另一组。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
struct Node
{
    int x,id;
    bool operator<(const Node& a)const
    {
        return x<a.x;
    }
};
int pre[maxm];
int n;
int findfa(int x)
{
    return pre[x]==x?x:pre[x]=findfa(pre[x]);
}
int main()
{
    int t,cas=1,x;
    cin>>t;
    while(t--)
    {
        cin>>n;
        priority_queue<Node>q;
        for(int i=1; i<=n; i++)
            pre[i]=i;
        for(int i=1; i<=n; i++)
        {
            cin>>x;
            q.push({x,i});
        }
        while(q.size()>=2&&q.top().x>=2)
        {
            Node a=q.top();
            q.pop();
            Node b=q.top();
            if(a.x==b.x)
            {
                q.pop();
                int rt=pre[findfa(a.id)]=findfa(b.id);
                q.push({a.x-1,rt});
            }
        }
        cout<<"Case "<<cas++<<": ";
        if(q.size()>=2)
        {
            cout<<"YES"<<endl;
            int rt=q.top().id;
            for(int i=1; i<=n; i++)
            {
                if(findfa(i)==rt)
                {
                     cout<<"0";
                }
                else
                {
                    cout<<"1";
                }
            }
            cout<<endl;
        }

        else
        {
            cout<<"NO"<<endl;
        }
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值