2017ACM/ICPC亞洲區瀋陽站(部分解題報告)
題意
計算四個整數的和
解題思路
使用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 }
題意
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 }
題意
相對題意不太好理解,給出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 }