2014 Multi-University Training Contest 8 部分题目解题报告

http://acm.hdu.edu.cn/search.php?field=problem&key=2014%20Multi-University%20Training%20Contest%208&source=1&searchmode=source

 

HDOJ 4945 2048

见:http://www.cnblogs.com/james47/p/3914893.html

 

HDOJ 4946 Area of Mushroom

题意:一个无限大的二维平面,有很多点,有坐标有速度,如果对于某个位置,有个点能比任何点严格地先到达,那么这个点属于它。问对于每个点是否能管辖无限大的面积。

分析:显然速度小的不用考虑。只需要考虑速度最大的那些点。然后最大速度为0也不用考虑。然后想想就发现,速度最大的点只有在它们组成的凸包边界上,才能管辖无限面积。要么是组成凸包的顶点,要么是凸包的边上的点(至少能管辖一条无限长射线)。然后就是求凸包了。还有一点就是如果两个速度最大的点重合,它们都不能算答案,但是还得把它们加入点集求凸包。不会计算几何。。然后不知道怎么把凸包的边上的点也包含到凸包里,于是就再后来又做一个o(n^2)的暴力判断。学长说只要把下面代码里的<=改成<就可以了,然后还要把重点去掉一个(排序完o(n)筛除),因为重点同时在栈内,会组成一个零向量,下一点不管是往什么方向偏转都会被加入栈,就跪了。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<vector>
  6 using namespace std;
  7 
  8 const double eps = 1e-8;
  9 inline int sign(double a){
 10     return a < -eps ? -1 : a > eps;
 11 }
 12 #define cross(p1, p2, p3) ((p2.x - p1.x) * (p3.y - p1.y) - (p3.x - p1.x) * (p2.y - p1.y))
 13 #define crossOp(p1, p2, p3) sign(cross(p1, p2, p3))
 14 struct stu{
 15     int x, y, v, id;
 16 } s[1000];
 17 struct point{
 18     int x, y, id;
 19     point(){}
 20     point(int _x, int _y): x(_x), y(_y){}
 21     bool operator < (const point &p) const{
 22         int c = sign(x - p.x);
 23         if (c) return c == -1;
 24         return sign(y - p.y) == -1;
 25     }
 26     point operator -(const point &p) const{
 27         return point(x - p.x, y - p.y);
 28     }
 29     double dot(const point &p) const{
 30         return x * p.x + y * p.y;
 31     }
 32 };
 33 int n, cas = 0;
 34 bool uni[1000];
 35 char ans[1000];
 36 
 37 int onSegment(point p, point q1, point q2)
 38 {
 39     return crossOp(q1, q2, p) == 0 && sign((p-q1).dot(p-q2)) <= 0;
 40 }
 41 vector<point> p, ans1;
 42 vector<point> convexHull(vector<point> ps)
 43 {
 44     int n = ps.size();
 45     if (n <= 1)
 46         return ps;
 47     sort(ps.begin(), ps.end());
 48     vector<point> qs;
 49     for (int i = 0; i < n; qs.push_back(ps[i++])){
 50         while(qs.size() > 1 && crossOp(qs[qs.size()-2], qs.back(), ps[i]) <= 0)
 51             qs.pop_back();
 52     }
 53     for (int i = n - 2, t = qs.size(); i >= 0; qs.push_back(ps[i--])){
 54         while((int)qs.size() > t && crossOp(qs[(int)qs.size()-2], qs.back(), ps[i]) <= 0)
 55             qs.pop_back();
 56     }
 57     qs.pop_back();
 58     return qs;
 59 }
 60 
 61 void output()
 62 {
 63     printf("Case #%d: %s\n", ++cas, ans);
 64     return ;
 65 }
 66 int main()
 67 {
 68     while(scanf("%d", &n) && n)
 69     {
 70         for (int i = 0; i < n; i ++) ans[i] = '0';
 71         ans[n] = '\0';
 72         int maxv = -1;
 73         for (int i = 0; i < n; i++){
 74             scanf("%d %d %d", &s[i].x, &s[i].y, &s[i].v);
 75             s[i].id = i;
 76             maxv = max(maxv, s[i].v);
 77         }
 78         if (maxv == 0){
 79             output();
 80             continue;
 81         }
 82         memset(uni, true, sizeof(uni));
 83         for (int i = 0; i < n; i++){
 84             if (uni[i])
 85                 for (int j = i+1; j < n; j++){
 86                     if (s[i].x == s[j].x && s[i].y == s[j].y && s[i].v == s[j].v)
 87                         uni[i] = uni[j] = false;
 88                 }
 89         }
 90   //      for (int i = 0; i < n; i++)
 91   //          if (uni[i]) printf("%d\n", i);
 92         p.clear();
 93         for (int i = 0; i < n; i++){
 94             if (s[i].v == maxv){
 95                 point tmp;
 96                 tmp.x = s[i].x;
 97                 tmp.y = s[i].y;
 98                 tmp.id = s[i].id;
 99                 p.push_back(tmp);
100             }
101         }
102        // for (int i = 0; i < p.size(); i++)
103        //     printf("%d %d %d\n", p[i].x, p[i].y, p[i].id);
104         ans1 = convexHull(p);
105 //        for (int i = 0; i < ans1.size(); i++)
106 //            printf("%d %d %d\n", ans1[i].x, ans1[i].y, ans1[i].id);
107         for (int i = 0; i < ans1.size(); i++)
108             if (uni[ans1[i].id]) ans[ans1[i].id] = '1';
109         for (int i = 0; i < n; i++)
110             if (ans[i] == '0' && s[i].v == maxv && uni[i]){
111                 point now;
112                 now.x = s[i].x;
113                 now.y = s[i].y;
114                 now.id = i;
115                 for (int j = 0; j < ans1.size()-1; j++)
116                     if (onSegment(now, ans1[j], ans1[j+1])){
117                         ans[i] = '1';
118                         break;
119                     }
120         if (onSegment(now, ans1[0], ans1[ans1.size()-1])){
121             ans[i] = '1';
122         }
123             }
124         output();
125     }
126     return 0;
127 }
View Code

 

 

HDOJ 4950 Monster

题意:每回合可以打怪兽,怪兽每轮回血。每轮可以选择休息或打,连续最多打k轮。问能否打死。

分析:作为一只勤劳的小蜜蜂,我们肯定要一直打k轮。那么就判断三种情况能不能打死就可以了。一个是一下就打死了,一个是k轮打死了,一个是磨血磨死的。

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 
 5 long long h, a, b, k;
 6 int main()
 7 {
 8     int cas = 0;
 9     while(scanf("%lld %lld %lld %lld", &h, &a, &b, &k))
10     {
11         if (h+a+b+k <= 0) break;
12         printf("Case #%d: ", ++cas);
13         bool yes = false;
14         if (h <= a) yes = true;
15         if (k*a - (k-1)*b >= h) yes = true;
16         if (k*a - (k+1)*b > 0) yes = true;
17         if (yes) puts("YES");
18         else puts("NO");
19     }
20     return 0;
21 }
View Code

 

 

HDOJ 4951 Multiplication table

题意:题面很复杂。就是给了一个p进制的一位乘法表,然后0...p-1重新做了个映射,给你新的乘法表,问你每个数在这个乘法表里是哪个数。

分析:第一眼没看懂,第二眼没看懂,第三眼猜懂了,感觉是很厉害的题。然后我们就发现0和1其实很好求,某一行如果全部相同,某一列十位和个位全部相同,那么他们对应的就是0,即0*0 = 00。然后1也是类似。题解给了一个很神奇的性质,并不想证明。。(目测也不好证),即特判完0和1,然后剩下的数,统计每行十位的不同数数目,那么这一行就是这个数目映射得到的。比如样例第0行十位的数有1,2,3三种,那么说明3映射成了0。(好吧我自己也没看懂自己写的)

然后出题人表示做法很多,比如你有了0和1,找p-1是哪个是很容易的,然后(p-1)*(p-1) = p(p-2) + 1,这样就找到p-2了,然后(p-1)(p-k) = p(p-k-1) + k,可以陆续找p-3,p-4。。就是一个递归的过程。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int p, cas = 0;
 7 int a[510][510], b[510][510];
 8 int ans[510];
 9 bool v[510];
10 int read()
11 {
12     int ret = 0;
13     char ch = getchar();
14     while(ch < '0' || ch > '9') ch = getchar();
15     while(ch >= '0' && ch <= '9'){
16         ret = ret * 10 + ch - '0';
17         ch = getchar();
18     }
19     return ret;
20 }
21 //
22 //int read()
23 //{
24 //    int ret = 0;
25 //    bool flag = 0;
26 //    char ch;
27 //    while(1){
28 //        ch = getchar();
29 //        if (ch >= '0' && ch <= '9') {flag = 1; ret = ret*10 + ch-'0';}
30 //        else if (flag) return ret;
31 //    }
32 //}
33 int find0()
34 {
35     for (int i = 0; i < p; i++){
36         bool flag = true;
37         int x = a[i][0];
38         for (int j = 0; j < p; j++)
39             if (x != a[i][j] || x != b[i][j] || x != a[j][i] || x != b[j][i]) {flag = 0; break;}
40         if (flag) return i;
41     }    
42 }
43 int find1()
44 {
45     for (int i = 0; i < p; i++){
46         if (a[i][i] == ans[0] && b[i][i] == i) return i;
47     }
48 }
49 int main()
50 {
51     while(scanf("%d", &p))
52     {
53         if (p == 0) break;
54         for (int i = 0; i < p; i++)
55             for (int j = 0; j < p; j++){
56                 //scanf("%d %d", &a[i][j], &b[i][j]);
57                 a[i][j] = read();b[i][j] = read();
58             }
59         ans[0] = find0();
60         ans[1] = find1();
61         for (int i = 0; i < p; i++)
62             if (i != ans[0] && i != ans[1]){
63                 memset(v, 0, sizeof(v));
64                 for (int j = 0; j < p; j++) v[a[i][j]] = true;
65                 int cnt = 0;
66                 for (int j = 0; j < p; j++) if (v[j]) cnt++;
67                 ans[cnt] = i;
68             }
69         printf("Case #%d: ", ++cas);
70         for (int i = 0; i < p; i++)
71             printf("%d%c", ans[i], i==p-1?'\n':' ');
72     }
73     return 0;
74 }
View Code

 

 

HDOJ 4952 Number Transformation

题意:给一个x和k,k是k次操作,第i次操作要求当前x是i的倍数,否则要变成一个比x大而且是i倍数的最小的数,问k次操作后x是多少。

分析:开始还觉得要求1..k的lcm,后来发现根本不对。。后来反正队友打了个表,发现暴力做到sqrt(x)就可以了,我也没听明白证明。。题解的思路倒是挺好理解。当前是第i次操作,那么就是(i+1)x' >= ix,变形一下就是 x' >= x-[x/i+1],然后如果x<i+1,x就不会变了,所以就暴力做。题解说是o(sqrt(n))的,也没说怎么证明。。

 1 #include<cstdio>
 2 
 3 long long x, k;
 4 int main()
 5 {
 6     int cas = 0;
 7     while(scanf("%lld %lld", &x, &k))
 8     {
 9         if (x == 0 && k == 0) break;
10         for (long long i = 1; i < k; i++){
11             if (x < i+1) break;
12             x = x - x/(i+1);
13         }
14         printf("Case #%d: %lld\n", ++cas, x*k);
15     }
16     return 0;
17 }
View Code

 

posted @ 2014-08-18 20:18  james47  阅读(218)  评论(0编辑  收藏  举报