2017ACM/ICPC亚洲区沈阳站(部分解题报告)

HDU 6225 Little Boxes

题意

计算四个整数的和

解题思路

使用Java大整数

 1 import java.math.BigInteger;
 2 import java.util.Scanner;
 3 
 4 /**
 5  *
 6  * @author reqaw
 7  */
 8 public class Main {
 9 
10     /**
11      * @param args the command line arguments
12      */
13     public static void main(String[] args) {
14         Scanner in = new Scanner(System.in);
15         int T;
16         T = in.nextInt();
17         while(T-- > 0) {
18             BigInteger a = in.nextBigInteger();
19             BigInteger b = in.nextBigInteger();
20             BigInteger c = in.nextBigInteger();
21             BigInteger d = in.nextBigInteger();
22             System.out.println(a.add(b).add(c).add(d));
23         }
24     }
25     
26 }

 HDU 6227 Rabbits

题意

n只兔子排在一条直线上,每只兔子都有一个坐标,最外边的兔子可以跳到两只兔子中间的空位上,每跳一次称为一次计数,问最多能够玩几次。

解题思路

从第二只兔子开始计算相邻的空位有几个,正着一遍,倒着一遍,取最大值即可。

 1 #include <cstdio>
 2 
 3 const int maxn = 500 + 10;
 4 int a[maxn];
 5 int main()
 6 {
 7     int T, n;
 8     scanf("%d", &T);
 9     while(T--) {
10         scanf("%d", &n);
11         for(int i = 0; i < n; i++) {
12             scanf("%d", &a[i]);
13         }
14         int s1 = 0;
15         for(int i = 1; i < n - 1; i++) {
16             s1 += a[i + 1] - a[i] - 1;
17         }
18         int s2 = 0;
19         for(int i = n - 2; i > 0; i--) {
20             s2 += a[i] - a[i - 1] - 1;
21         }
22         printf("%d\n", s1 > s2 ? s1 : s2);
23     }
24     return 0;
25 }

 HDU 6222 Heron and His Triangle

题意

先定义了一个H三角形,它的三条边由连续的三个整数构成,即t-1, t , t+1,并且它的面积是一个整数。给出一个整数n(最大可能是10^30),问满足t>=n的最小t是多少。

解题思路

先暴力打出前几个满足条件的t,仔细观察发现满足一个规律,res[i] = res[i - 1] * 4 - res[i - 2];由于数字很大,使用Java大数。

 1 /*先暴力出前几项*/
 2 #include <cstdio>
 3 #include <cmath>
 4 typedef unsigned long long ull;
 5 int main()
 6 {
 7     for(ull t = 4; t <= 1000000; t++) {
 8         ull a = t - 1;
 9         ull b = t;
10         ull c = t + 1;
11         ull p = (a + b + c) / 2;
12         ull k = p * (p - a) * (p - b) * (p - c);
13         if((ull)sqrt(k) * (ull)sqrt(k) == k) {
14             printf("%lld\n", t);
15         }
16     }
17     return 0;
18 }

找到规律后打表

 1 import java.math.BigInteger;
 2 import java.util.Scanner;
 3 
 4 /**
 5  *
 6  * @author reqaw
 7  */
 8 public class Main {
 9 
10     /**
11      * @param args the command line arguments
12      */
13     public static void main(String[] args) {
14         BigInteger res[] = new BigInteger[100];
15         res[0] = BigInteger.valueOf(4L);
16         res[1] = BigInteger.valueOf(14L);
17         for(int i = 2; i < 100; i++) {
18             res[i] = res[i - 1].multiply(res[0]).subtract(res[i - 2]);
19             //System.out.println(res[i]);
20         }
21         Scanner cin = new Scanner(System.in);
22         int T = cin.nextInt();
23         while(T-- > 0) {
24             BigInteger n = cin.nextBigInteger();
25             for(int i = 0; i < 100; i++) {
26                 if(res[i].compareTo(n) >= 0) {
27                     System.out.println(res[i]);
28                     break;
29                 }
30             }
31         }
32     }
33 
34 }

 HDU 6219 Empty Convex Polygons

题意

给出n个点,求由这n个点组成的最大空凸包的面积是多少。

解题思路

使用求解最大空凸包的模板,基本思想是穷举所 要求解的空凸包的最低最左点(先保证最低,再保证最左)。

  对于每一个穷举到的点v,进行动态规划,用opt[i][j]表示符合如下限制的凸包中的最大面积:

  在凸包上v顺时针过来第一个点是i,并且i顺时针过来第一个点k不在i->j的左手域(k 可以等于 j)。

  1 #include <cstdio>
  2 #include <cmath>
  3 #include <algorithm>
  4 using namespace std;
  5 
  6 const int maxn = 100;
  7 const double zero = 1e-8;
  8 
  9 struct Vector {
 10     double x, y;
 11 };
 12 
 13 inline Vector operator - (Vector a, Vector b) {
 14     Vector c;
 15     c.x = a.x - b.x;
 16     c.y = a.y - b.y;
 17     return c;
 18 }
 19 inline double Sqr(double a) {
 20     return a * a;
 21 }
 22 inline int Sign(double a) {
 23     if(fabs(a) <= zero)    return 0;
 24     return a < 0 ? -1 : 1;
 25 }
 26 inline bool operator < (Vector a, Vector b) {
 27     return Sign(b.y - a.y) > 0 || Sign(b.y - a.y) == 0 && Sign(b.x - a.x) > 0;
 28 }
 29 inline double Max(double a, double b) {
 30     return a > b ? a : b;
 31 }
 32 inline double Length(Vector a) {
 33     return sqrt(Sqr(a.x) + Sqr(a.y));
 34 }
 35 inline double Cross(Vector a, Vector b) {
 36     return a.x * b.y - a.y * b.x;
 37 }
 38 
 39 Vector dot[maxn], List[maxn];
 40 double opt[maxn][maxn];
 41 int seq[maxn];
 42 int n, len;
 43 double ans;
 44 
 45 bool Compare(Vector a, Vector b) {
 46     int temp = Sign(Cross(a, b));
 47     if(temp != 0) return temp > 0;
 48     temp = Sign(Length(b) - Length(a));
 49     return temp > 0;
 50 }
 51 
 52 void Solve(int vv) {
 53     int t, i, j, _len;
 54     for(i = len = 0; i < n; i++) {
 55         if(dot[vv] < dot[i])
 56             List[len++] = dot[i] - dot[vv];
 57     }
 58     for(i = 0; i < len; i++) {
 59         for(j = 0; j < len; j++) {
 60             opt[i][j] = 0;
 61         }
 62     }
 63     sort(List, List + len, Compare);
 64     double v;
 65     for(t = 1; t < len; t++) {
 66         _len = 0;
 67         for(i = t - 1; i >= 0 && Sign(Cross(List[t], List[i])) == 0; i--);
 68          
 69         while(i >= 0) {
 70             v = Cross(List[i], List[t]) / 2;
 71             seq[_len++] = i;
 72             for(j = i - 1; j >= 0 && Sign(Cross(List[i] - List[t], 
 73             List[j] - List[t])) > 0; j--);
 74             if(j >= 0)
 75                 v += opt[i][j];    
 76             ans = Max(ans, v);
 77             opt[t][i] = v;
 78             i = j;
 79         }
 80         for(i = _len - 2; i >= 0; i--) {
 81             opt[t][seq[i]] = Max(opt[t][seq[i]], opt[t][seq[i + 1]]);
 82         }
 83     }
 84 }
 85 
 86 int i;
 87 double Empty() {
 88     ans = 0;
 89     for(i = 0; i < n; i++) {
 90         Solve(i);
 91     }
 92     return ans;
 93 }
 94 
 95 int main()
 96 {
 97     int T;
 98     scanf("%d", &T);
 99     while(T--) {
100         scanf("%d", &n);
101         for(i = 0; i < n; i++) {
102             scanf("%lf%lf", &dot[i].x, &dot[i].y);
103         }    
104         printf("%.1lf\n", Empty()); 
105     }
106     return 0;
107 }

HDU 6228 Tree

题意

相对题意不太好理解,给出n个顶点的无根树,也即无向图,k种颜色,问将每一个顶点染成一种颜色,然后将同种颜色的顶点用最少的边连起来(以及每两点间是最短路)组成E,有k中颜色,也就是每一种染色方案有E1,E2...Ek,问它们的交集(边的交集)最大是多少

解题思路

关键是题意的转化,可以想象的是在一个无根树中,给每个点染上k种颜色中的一种,然后将颜色相同的点使用最短路连接起来,连接起来的边算刷一遍,最后求的就是所有的边中,次数被刷k次及其以上的边最多有多少条。

具体实现时,先明白如果该边满足条件,那么两端的点都需要大于k个才行,我们使用深搜计算每个节点的子孙数即可。

 1 #include <cstdio>
 2 #include <vector>
 3 using namespace std;
 4 
 5 const int maxn = 200000 + 10;
 6 int n, k;
 7 int ans;
 8 vector<int> e[maxn];
 9 int num[maxn];
10 
11 void dfs(int u, int pre) {
12     num[u] = 1;
13     int eus = e[u].size();
14     for(int i = 0; i < eus; i++) {
15         int v = e[u][i];
16         if(v == pre)    continue;
17         dfs(v, u);
18         
19         num[u] += num[v];//递归返回时将u的子孙结点数加上 
20         if(num[v] >= k && n - num[v] >= k)    ans++;
21     }    
22 }
23 
24 int main()
25 {
26     int T;
27     scanf("%d", &T);
28     while(T--) {
29         scanf("%d%d", &n, &k);
30         for(int i = 0; i < maxn; i++) {
31             e[i].clear();
32         }
33         for(int i = 0; i < n - 1; i++) {
34             int u, v;
35             scanf("%d%d", &u, &v);
36             e[u].push_back(v);
37             e[v].push_back(u);            
38         }
39         ans = 0;
40         dfs(1, -1);
41         printf("%d\n", ans);
42     }    
43     return 0;
44 }

猜你喜欢

转载自www.cnblogs.com/wenzhixin/p/9794497.html