目录
HDU 6560 F.The Hermit(思维:数学不等式判结论)
HDU 6559 The Tower(解析几何)
题意:
给出一个圆锥,底面圆心在原点(0,0,0),给出圆锥外一点(x0,y0,z0)(保证为圆锥外一点),以及该点在各个方向上的移动速度(vx,vy,vz)。求该点撞击在圆锥面上时的时间t。
思路:
假设撞击到圆锥上的点是A(x,y,z)。圆锥得横截面都是圆,都满足。
平面图:
由相似三角形得:,即。
假设撞击时间为t,则撞击点A的坐标是()。
将A点代入圆的方程:。
化简过程:
能先算的先算出来:和。
平方展开,提取公因子,,剩下部分是常数,每一部分的系数分别是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;
经过化简得到一个一元二次方程:。
求解t:。
得到两个值t1,t2,设t1<t2:题目保证撞击点存在,并且撞击点的高,所以如果,则输出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站的信号。由于某种未知的原因,能够接收到第i站信号的左边界是非递减的,即。
如果电台K同时满足以下两个条件,该电台就可以接收到i台的完美信号:
(1)并且(k在i的左边且在i范围内)
(2)存在另一站,使得k和i都能接收到j站的信号,且k和j站之间的距离大于或等于j站和i之间的距离。
求每个i站,有多少站可以收到i站的完美信号,输出它们的异或和。
思路:
根据题意总结条件(k,j,i 三个电台之间关系):
(1)
(2)
(3)
(4)
(5)
(6)
由(1)(6)可知:(3)在(2)的情况下显然成立,因此可删去(3)。
由(5)可知:(4)在(3)的情况下显然成立,因此可删去(4)。
最后留下的就只有(1),(2),(5),(6)。
(1)
(2)
(5)
(6)
总结K电台的范围:
(1)
(2)
(3)(解不等式(5)得)
(4)因为 j < i,所以 j >= 2*j - i。
所以k得范围是【】,每个i站,有站可以收到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个砝码,每个砝码有一个权值,表示重量为,判断是否有可能将砝码分为两组,满足每组的重量都大于等于。如果有则输出方案(0表示在第0组,1表示在第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;
}