ACM-ICPC 2017 Asia Shenyang Solution
A: BBP Formula
https://www.cnblogs.com/LzyRapx/p/7802790.html
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 6 inline ll qpow(ll x, ll n, ll mod) 7 { 8 ll base = x; 9 ll ans = 1; 10 while (n) 11 { 12 if (n & 1) ans = (ans * base) % mod; 13 base = base * base % mod; 14 n >>= 1; 15 } 16 return ans; 17 } 18 19 inline double BBP(int n, ll k, ll b) 20 { 21 double res = 0.0; 22 for (int i = 0; i <= n; ++i) 23 res += qpow(16, n - i, (8 * i + b)) * 1.0 / (8 * i + b); 24 for (int i = n + 1; i <= (n + 500); ++i) 25 res += powf(16, n - i) * 1.0 / (8 * i + b); 26 return k * res; 27 } 28 29 inline char print(double tmp) 30 { 31 int x = int(tmp); 32 if (x >= 0 && x <= 9) 33 return x + '0'; 34 return x - 10 + 'A'; 35 } 36 37 int t, n; 38 39 inline void Run() 40 { 41 scanf("%d", &t); 42 for (int kase = 1; kase <= t; ++kase) 43 { 44 scanf("%d", &n); --n; 45 double ans = BBP(n, 4, 1) - BBP(n, 2, 4) - BBP(n, 1, 5) - BBP(n, 1, 6); 46 ans = ans - (int)ans; 47 if (ans < 0) ans += 1.0; 48 ans *= 16.0; 49 printf("Case #%d: %d %c\n", kase, n + 1, print(ans)); 50 } 51 } 52 53 int main() 54 { 55 #ifdef LOCAL 56 freopen("Test.in", "r", stdin); 57 #endif 58 59 Run(); 60 61 return 0; 62 }
B: Bridge
留坑。
C: Empty Convex Polygons
留坑。
D: Defense of the Ancients
留坑。
E: Five-roune Show Hand
留坑。
F:Heron and His Triangle
题意:给出一个n,找出一个最小的t满足 t >= n 并且 t-1 t t + 1 三条边组成的三角形的面积的整数
思路:根据海伦公式,然后打表,找出前几项是
4
14
52
194
724
然后发现 F(n) = 4F(n - 1) - F(n - 2)
可以发现,这个数增长的很快,60多项就会超过10^30了 用JAVA打个表,然后暴力找或者二分找都可以
1 import java.math.BigInteger; 2 import java.util.Scanner; 3 4 public class Main 5 { 6 7 public static void main(String[] args) 8 { 9 Scanner in = new Scanner(System.in); 10 BigInteger ans[] = new BigInteger[200 + 10]; 11 ans[0] = BigInteger.valueOf(4); 12 ans[1] = BigInteger.valueOf(14); 13 for(int i = 2; i <= 200; ++i) 14 { 15 ans[i] = ans[i - 1].multiply(BigInteger.valueOf(4)); 16 ans[i] = ans[i].subtract(ans[i - 2]); 17 } 18 int T = in.nextInt(); 19 for(int cas = 1; cas <= T; ++cas) 20 { 21 BigInteger n = in.nextBigInteger(); 22 for(int i = 0; i <= 200; ++i) 23 { 24 if(ans[i].compareTo(n) >= 0) 25 { 26 System.out.println(ans[i]); 27 break; 28 } 29 } 30 } 31 } 32 }
G: Infinite Fraction Path
题意:给出长度为n的字符串,对于第i位的数,它和第(i^2 + 1) % n位的数有一条有向边,从一个数出发,走n - 1 步,得到一个长度为n的字符串,输出字典树最大的那个
思路:考虑搜索
贪心的想法肯定是第一步是字母序最大的那个字母开始
两条剪枝:
第一条:每次扩展一步,如果有一个点扩展出来到这一位的字母小于其它点过来的 剪掉
第二条:每次扩展一步,如果下标被相同步数到达这里的访问过,剪掉
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 200010 6 typedef long long ll; 7 8 int n; 9 char str[N]; 10 char ans[N]; 11 int used[N]; 12 13 struct node{ 14 ll idx; 15 int step; 16 inline node(){} 17 inline node(ll idx, int step) :idx(idx), step(step){} 18 }; 19 20 queue<node>q; 21 22 inline void Init() 23 { 24 while(!q.empty()) q.pop(); 25 memset(ans, 0, sizeof ans); 26 memset(used, 0, sizeof used); 27 } 28 29 inline void BFS() 30 { 31 node st, now; 32 while(!q.empty()) 33 { 34 st = q.front(); 35 q.pop(); 36 if(st.step > n - 1) continue; 37 if(str[st.idx] < ans[st.step]) continue; 38 if(str[st.idx] > ans[st.step]) 39 ans[st.step] = str[st.idx]; 40 now.idx = (st.idx * st.idx + 1) % n; 41 now.step = st.step + 1; 42 if(str[now.idx] < ans[now.step]) continue; 43 if(used[now.idx] == now.step) continue; 44 used[now.idx] = now.step; 45 q.push(now); 46 if(str[now.idx] > ans[now.step]) 47 ans[now.step] = str[now.idx]; 48 } 49 } 50 51 int main() 52 { 53 int t; 54 scanf("%d",&t); 55 for(int cas = 1; cas <= t; ++cas) 56 { 57 Init(); 58 scanf("%d", &n); 59 scanf("%s", str); 60 char Max = 0; 61 for(int i = 0; i < n; ++i) 62 { 63 Max = max(Max, str[i]); 64 } 65 for(int i = 0; i < n; ++i) 66 { 67 if(str[i] == Max) 68 q.push(node(i, 0)); 69 } 70 BFS(); 71 printf("Case #%d: ", cas); 72 for(int i = 0; i < n; ++i) 73 { 74 printf("%c",ans[i]); 75 } 76 printf("\n"); 77 } 78 return 0; 79 }
H:Legends of the Three Kingdoms
留坑。
I:Little Boses
ull的范围是2 ^ 64 - 1
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 #define ull unsigned long long 5 6 int t; 7 ull a[4]; 8 9 inline bool check() 10 { 11 ull D = 1ull << 62; 12 for (int i = 0; i < 4; ++i) 13 if (a[i] != D) 14 return false; 15 return true; 16 } 17 18 int main() 19 { 20 scanf("%d", &t); 21 while (t--) 22 { 23 for (int i = 0; i < 4; ++i) scanf("%llu", a + i); 24 if (check()) 25 { 26 puts("18446744073709551616"); 27 continue; 28 } 29 else 30 { 31 ull sum = 0; 32 for (int i = 0; i < 4; ++i) sum += a[i]; 33 printf("%llu\n", sum); 34 } 35 } 36 return 0; 37 }
J:New Self-describing Sequence
留坑。
K:Rabbits
题意:有n只小兔子,如果两个小兔子中间有间隙,那么在这两个小兔子之外的兔子可以跳到某一个间隙中,求最多能跳多少步
思路:显然 答案是 最左边那个小兔子到最右边的左边的小兔子的间隙数和最右边小兔子到最左边的右边的小兔子的间隙取max
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 510 6 7 int t; 8 int n; 9 int arr[N]; 10 11 int main() 12 { 13 scanf("%d", &t); 14 while (t--) 15 { 16 scanf("%d", &n); 17 for (int i = 1; i <= n; ++i) 18 scanf("%d", arr + i); 19 int ans = 0; 20 ans = arr[n - 1] - arr[1] + - n + 2; 21 ans = max(ans, arr[n] - arr[2] - n + 2); 22 printf("%d\n", ans); 23 } 24 return 0; 25 }
L:Tree
题意:给出一棵树,k种颜色,每种颜色的边集是选取最少的边使得这些边覆盖所有这种颜色的点,求k中颜色的边集并
思路:显然,如果一条边存在于所有颜色的边集当中,那么它连接的两边的端点个数一定>= k
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 200010 6 7 struct node 8 { 9 int to, nx; 10 inline node() {} 11 inline node(int to, int nx) : to(to), nx(nx) {} 12 }edge[N << 1]; 13 14 int head[N], pos; 15 int used[N]; 16 int sum[N]; 17 18 inline void Init() 19 { 20 memset(head, -1, sizeof head); 21 memset(used, 0, sizeof used); 22 memset(sum, 0, sizeof sum); 23 pos = 0; 24 } 25 26 inline void addedge(int u, int v) 27 { 28 edge[++pos] = node(v, head[u]); head[u] = pos; 29 edge[++pos] = node(u, head[v]); head[v] = pos; 30 } 31 32 int ans; 33 int t, n, k; 34 35 inline void DFS(int u) 36 { 37 used[u] = 1; 38 sum[u] = 1; 39 for (int it = head[u]; ~it; it = edge[it].nx) 40 { 41 int v = edge[it].to; 42 if (used[v] == 1) continue; 43 DFS(v); 44 sum[u] += sum[v]; 45 } 46 if (sum[u] >= k && (n - sum[u] >= k)) ++ans; 47 } 48 49 int main() 50 { 51 scanf("%d", &t); 52 while (t--) 53 { 54 scanf("%d%d", &n, &k); 55 Init(); 56 for (int i = 1, u, v; i < n; ++i) 57 { 58 scanf("%d%d", &u, &v); 59 addedge(u, v); 60 } 61 ans = 0; 62 DFS(1); 63 printf("%d\n", ans); 64 65 } 66 return 0; 67 }
M:Wandering Robots
题意:给出n * n 的矩形,有k个障碍物,机器人刚开始在(0, 0) 点,它会等概率的选择停留在原地,或者走向相邻的可走的格子(即没有障碍物的),时间过去了很久,求机器人在(x, y) (x + y >= n - 1) 的点的概率
思路:LTS大神推出答案就是 (满足条件的点的可能性) / (所有点的可能性)
先公式求出所有点的可能性
然后枚举障碍物,减去多加的可能性
首先障碍物本身要减去自身的可能性,如果它的相邻点不是障碍物,还要减去一
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 typedef pair <int, int> pii; 7 8 inline ll gcd(ll a, ll b) 9 { 10 while(b ^= a ^= b ^= a %= b); 11 return a; 12 } 13 14 ll n, k; 15 16 map <pii, int> mp; 17 18 int Move[][2] = 19 { 20 0, 1, 21 0,-1, 22 1, 0, 23 -1, 0, 24 }; 25 26 inline bool ok(int x, int y) 27 { 28 if (x < 0 || x >= n || y < 0 || y >= n) return false; 29 return true; 30 } 31 32 int main() 33 { 34 int t; 35 scanf("%d",&t); 36 for(int cas = 1; cas <= t; ++cas) 37 { 38 scanf("%lld %lld", &n, &k); 39 mp.clear(); 40 for (int i = 1, x, y; i <= k; ++i) 41 { 42 scanf("%d%d", &x, &y); 43 mp[pii(x, y)] = 1; 44 } 45 printf("Case #%d: ", cas); 46 if (n == 1) 47 { 48 if (k == 0) 49 puts("1/1"); 50 else 51 puts("0/0"); 52 } 53 else 54 { 55 ll fenmu = (n - 2) * (n - 2) * 5 + 16 * (n - 2) + 12; 56 ll fenzi = (n - 2) * 8 + 5 * (n - 1) * (n - 2) / 2 + 9; 57 for (map<pii, int>::iterator it = mp.begin(); it != mp.end(); ++it) 58 { 59 int x = it->first.first, y = it->first.second; 60 int tmp = 5; 61 if (x == 0 || x == n - 1) 62 tmp--; 63 if (y == 0 || y == n - 1) 64 tmp--; 65 fenmu -= tmp; 66 if (x + y >= n - 1) 67 fenzi -= tmp; 68 for (int i = 0; i < 4; ++i) 69 { 70 int dx = x + Move[i][0]; 71 int dy = y + Move[i][1]; 72 if (!ok(dx, dy)) continue; 73 if (mp.count(pii(dx, dy)) == 1) continue; 74 --fenmu; 75 if (dx + dy >= n - 1) 76 --fenzi; 77 } 78 } 79 ll G = gcd(fenzi, fenmu); 80 fenzi /= G, fenmu /= G; 81 printf("%lld/%lld\n", fenzi, fenmu); 82 } 83 } 84 return 0; 85 }