[SGU110 Dungeon]【计算几何】【模拟】【球面反射】

【题目大意】
给定n个球,与一条射线,然后让你模拟这个射线在这些球之间弹,输出弹到得球的标号。如果弹到<=10个就有多少输出多少。否则,输出前10个+ 'etc.'

【算法分析】
我们用三维向量来解决。
1、首先根据点到球心距离等于半径 + 我们的运动向量列出一个方程,解这个一元二次方程可以得到我们什么时候碰到这个球。
2、然后碰到以后呢。就把射线起点,球上的碰触点,球心这三个点,搞成一个平面,然后再在上面以向量:碰触点->球心作为法线,考虑镜面反射即可。
然后这里我再次用了一个解方程+向量伸缩的方法得到了他反射以后的向量。

关于第二步的反射部分,我们所知道的条件有:入射向量,法线向量。我的做法具体就是先构造出向量tmp=发现向量-入射向量。并使得|tmp|=|入射向量|。然后就可以通过一些几何知识来搞了。

【其它】WA了几遍,因为我解一元二次方程的时候判断无解写得是delta<1e-6,然后如果1e-6<=delta<0的话,我就先将它置为0再进行后面的计算。
我改成delta<0就为无解就AC了。T_T。。。精度什么的,最讨厌了。

【CODE】
#include #include #include #include #include #define dis(A,B) sqrt( (A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z) )
#define Sqr(x) ((x)*(x))
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
using namespace std;
const int N=1005;
const double eps=1e-6;
int n;
double res1,res2;
struct Circle{double x,y,z,r;}a[N];
struct Point{double x,y,z;}p,fx;

void init(){
     scanf("%d",&n);
     int i,j;
     for (i=1;i<=n;i++)
       cin >> a[i].x >> a[i].y >> a[i].z >> a[i].r;
     cin >> p.x >> p.y >> p.z >> fx.x >> fx.y >> fx.z;
     fx.x-=p.x;
     fx.y-=p.y;
     fx.z-=p.z;
}

Point Get_Point(double rate){
      Point res;
      res.x=fx.x*rate+p.x;
      res.y=fx.y*rate+p.y;
      res.z=fx.z*rate+p.z;
      return res;
}

double Get_Meet_Rate(Circle Cir){
       double a,b,c,delta,x1,x2;
       Point tmp;
       tmp.x=Cir.x-p.x;
       tmp.y=Cir.y-p.y;
       tmp.z=Cir.z-p.z;
       a=Sqr(fx.x)+Sqr(fx.y)+Sqr(fx.z);
       b=-2*(fx.x*tmp.x + fx.y*tmp.y + fx.z*tmp.z);
       c=-Sqr(Cir.r)+Sqr(tmp.x)+Sqr(tmp.y)+Sqr(tmp.z);
       delta=b*b-4*a*c;
       if (delta<0) return 1e22;
       delta=sqrt(delta);
       x1=(-b+delta)/(2*a);
       x2=(-b-delta)/(2*a);
       if (x1<=eps) x1=1e22;
       if (x2<=eps) x2=1e22;
       res1=x1; res2=x2;
       return min(x1,x2);
}

Point opposite(Point tmp){
      Point res;
      res.x=-tmp.x;
      res.y=-tmp.y;
      res.z=-tmp.z;
      return res;
}

void Reflect(int i,double rate){
     Point cross=Get_Point(rate);
     Get_Meet_Rate(a[i]);
     if ( fabs(res1-res2) < eps ){
       p=cross;
       return;
     }
     Point normal_line,tmp;
     normal_line.x=(a[i].x-cross.x)/2;
     normal_line.y=(a[i].y-cross.y)/2;
     normal_line.z=(a[i].z-cross.z)/2;
     double t=Sqr(normal_line.x)+Sqr(normal_line.y)+Sqr(normal_line.z);
     t/=(normal_line.x*fx.x + normal_line.y*fx.y + normal_line.z*fx.z);
     fx.x*=t; fx.y*=t; fx.z*=t;
     normal_line.x*=2;
     normal_line.y*=2;
     normal_line.z*=2;
    
     tmp.x=normal_line.x-fx.x;
     tmp.y=normal_line.y-fx.y;
     tmp.z=normal_line.z-fx.z;
    
     fx=opposite(tmp);
     p=cross;
    
     bool flag=false;
     if (fx.x>10) flag=true;
     if (fx.y>10) flag=true;
     if (fx.z>10) flag=true;
     if (!flag){
       fx.x*=10;
       fx.y*=10;
       fx.z*=10;
     }
}

void work(){
     int i,best,cnt=0;
     double rate,tmp;
     while (1){
           rate=1e20;
           best=0;
           for (i=1;i<=n;i++){
               tmp=Get_Meet_Rate(a[i]);
               if (tmp                 rate=tmp;
                 best=i;
               }
           }
           if (best==0) break;
           Reflect(best,rate);
           cnt++;
           if (cnt>10) break;
           if (cnt!=1) cout << " ";
           cout << best;
     }
     if (cnt>10) cout << " etc." << endl;
            else cout << endl;
}

int main(){
    init();
    work();
    return 0;
}

[HDOJ2966 In case of failure]【平面每个点的最近点对】【暴力T_T】

【题目大意】
给定n个点,求每个点到离他最近点的距离。
【算法分析】
V图什么的,最讨厌了。。。
我直接就暴力了。。。
按x把点排序,然后按j递增序,枚举i-j的点和i+j的点。如果(a[i].x-a[i-j].x)^2 > dis && (a[i].x-a[i+j].x)^2 > dis
那么就break吧。
复杂度还是n^2的。
其中dis为之前枚举所得的较优解。
【其它】果断排到超级后面。
叉姐说,见到题目要先水一水,水不过再切。。。= =
【CODE】
#include #include #include #include #define dis(A,B) ( (lld)(A.x-B.x)*(lld)(A.x-B.x) + (lld)(A.y-B.y)*(lld)(A.y-B.y) )
#define Sqr(x) ((lld)(x)*(lld)(x))
using namespace std;
typedef long long lld;
const lld INF=(lld)(2000000000)*(lld)(2000000000);
int Tc;
int n;
struct Point{int x,y,pos; lld dis;}a[105555];

bool cmp(Point A,Point B){
return A.x}

void init(){
scanf("%d",&n);
int i;
for (i=1;i<=n;i++){
scanf("%d%d",&a[i].x,&a[i].y);
a[i].pos=i;
}
sort(a+1,a+n+1,cmp);
}

void work(){
int i,j;
bool flag;
lld tmp;
for (i=1;i<=n;i++){
a[i].dis=INF;
for (j=1;(i-j>=1 || i+j<=n);j++){
flag=false;
if (i-j>=1 && Sqr(a[i].x-a[i-j].x) tmp=dis(a[i],a[i-j]);
if (tmp flag=true;
}
if (i+j<=n && Sqr(a[i+j].x-a[i].x) tmp=dis(a[i],a[i+j]);
if (tmp flag=true;
}
if (!flag) break;
}
}
}

bool cmp2(Point A,Point B){
return A.pos}

void output(){
sort(a+1,a+n+1,cmp2);
for (int i=1;i<=n;i++)
printf("%I64dn",a[i].dis);
}

int main(){
scanf("%d",&Tc);
for (int i=0;i init();
work();
output();
}
}

[SGU108 Self-numbers 2]【枚举】【常数题】

【算法分析】

就是类似筛法那样弄下去。但是特殊的是i只会影响到一个>i的数。

而且之多+6*9。所以,我们可以开滚动数组来弄。(开10^7 bool会MLE)

然后模拟高精度那样+1。就可以很方便地维护该数所指的下一个数next。

【其它】速度貌似不错。180+MS。

【Record】

1057066 13.08.10 12:37 edward 108 .CPP Accepted 186 ms 43 kb

【CODE】

#include

[SGU106 The Equation]【欧几里得拓展算法解二元一次方程】

【题目大意】

给定ax+by+c=0。求x1<=x<=x2 && y1<=y<=y2的解有多少组。

【算法分析】

见到缺了这种例题,又没A这题,那么就做一下。

例题系列。

首先判断掉a和b中存在0的情况。然后exgcd解出ax+by=gcd(a,b)的一个初始解,

然后假如-c%gcd(a,b)!=0。那么无解。否则a/=g b/=g c/=g。然后x就只能+-b,y对应地+-a。然后用个除法搞一下就可以了。

一开始我后面取范围用倍增算法,就是2进制步长那种跨越的。第3个点居然就TLE了= =。

【时间复杂度】O(lg (x+y))

【空间复杂度】O(1)

【CODE】

#include

NOI后记

这次是我第一次,也是最后一次NOI
由于我是夏令营选手,然后GD夏令营有5个人。每个宿舍能装4个人。5%4==1?
没错,我就是那个1
然后被果断发配到与3个黑龙江夏令营选手一起= =。

7.31
我们很晚才报道。然后与何神(我们尊称为小赖神)等吃了晚饭。。。
然后回到宿舍。发现没有拖鞋洗澡。疼,然后果断去买。
买完回来发现那个厕所激动得停不下来了,一直冲水,疼。。。
然后我们把他活生生拔出来以后才停了。过了一会儿,听过隔壁宿舍的厕所也开始激动了。于是心里平衡一点。。。
然后上上网,就睡了。

8.1
早上开幕式。。。然后各种讲话。让我感觉比较疼的是,映像中各个上去发表讲话的人里,只有1人脱稿。那就是海尔的经理。毕竟还是商人这方便要求比较高啊。。。
然后中午再围观了一下笔试题。下午就去笔试了。
笔试基本是送分。然后这次得了100。
然后那个练习赛的话,前面那题一看到题目搞了n^4的,可以AC了。然后提交答案没搞。。。出来一听,其他人都是O(n)的。。。我真蒟蒻+疼。
然后晚上很早就睡了。不过睡不惯那么硬的枕头。

8.2 Day1
比较紧张。然后看了第一题,哇。。。居然有80分是送人的。高高兴兴搞完,就不理第一题了。
然后看了第二题,感觉有点混乱。
写了个n^3的dp。然后看第3题。
大概思考了20秒。。。很神奇地认为是平面图最小割。但是那个两个不同方向边的不太会搞的样子啊。
然后我记得衡阳八中1001有人用sap依然可以卡过。。。甚至比我的spfa还快。于是我果断写了bfs预处理标号的sap。这样就能保证这题有80分了。
然后回来搞第二题。
第二题我一开始写了n^3的dp。后来用作对拍只用。感觉还是挺好的。
然后我YY了一会儿,想到了二分答案+平衡树的做法。然后就果断敲了。
后来写好以后。。。不会写对拍程序= =。。。我当时就泪奔了。。。
然后回忆笔试内容,知道运行一个文件时./xxxxx 然后我用C++的system("");试了一会儿。
搞的很囧。原因是我是这样写的:system("./makedata.exe");
然后。。。Linux的可执行文件原来是可以没后缀名的。。。
试了一会儿终于可以开始对拍了。
然后平衡树各种写庛= =。
调了N久终于正确了。然后好像我就没做什么了。就是各种对拍与检查文件名等。
然后下午拿到成绩。。。
80+30+90=200。
果断第二题zheyi了。。。70分的算法被我活生生写成30分。。。手测10^5那几个点都是2.xxx s。然后时限是2s。后来叉姐说不用struct封装那个平衡树,可以快3倍= =。。。我当时就囧了。

8.3 社会实践活动
上午去了蓬莱极地世界。。。然后围观各种鱼。然后就走了。囧。
下午去了那个啥沙滩。。。。看着海水泛着绿色的各种草还是啥的。。。果断留在沙滩上。。。
后来WY神牛在那各种打蜻蜓,但是一只都没搞到。表示蜻蜓敏捷太高。。。
后来省队众牛在各种讨论如何制止卢神牛进省队的伟大计划。。。叉姐猜测可能栋栋会因为没见过由卢神牛造成的大场面而泪流满面。。。
然后就回去洗洗睡了。

8.4 Day2
这次一拿到试题。先把所有题都看了一遍。
囧,一题都不会= =。然后貌似记得哪个大牛说要先搞提交答案题。然后我就先搞了。
然后我想了两个贪心的。一个是找距离最近的虾去抓。另一个是找追上时间最短的虾去抓。然后把所有数据都运行了一次,取较优值。
我表示没做过提交答案题。。。不知道要看数据。= =。
然后暴力的第一题和第二题。
然后第二题n=2的情况搞了好久。。。还是没搞出来。主要是顺指针逆时针走的和蛇形走的之间各种嵌套什么的。
然后想给第二题加一个连通性剪枝的。然后后来觉得反正搜索过不了多少,就没加。(事实证明,有30分)
第一题看了一下。决定分段。首先n<=10的30分一定要拿到。然后其他的就乱搞。
我先对那个先后限制当成权为1的有向边。然后Floyed了一下。
然后按照每个点卡的紧要程度拍了下序,然后搜索出一个可行解。那些最前可以是多少就放弃了。
全部输出1。

然后下午看成绩46+30+54=130。感觉第二题的30分比较zheyi。。。其他没什么了。
最后我也不知道什么rank的东西。感觉不知道有没有银牌。
然后后来听到说金牌貌似479,那我就觉得应该有银牌了。

8.5 之后
然后后面的就是各种找学校。
由于我比较囧。。。NOIP没有1=,又是夏令营选手。虽然NOI有430分。但是那个没有1=就没有保送资格。然后只能协商说等拿到一等以后再要。。。

然后现在离NOIP还有两个月。。。这两个月要好好学习文化课。。。毕竟NOIP虽然几乎不可能挂,但是毕竟没拿到保送。。。老师也不会允许我文化课不太努力的= =。。。。
现在。。。回去上文化课。现在就一个字:疼。。。。