1. 程式人生 > >2017ACM/ICPC亞洲區瀋陽站(部分解題報告)

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 }