當前位置:
首頁 >
BestCoder-Round#38
發布時間:2025/3/15
32
豆豆
生活随笔
收集整理的這篇文章主要介紹了
BestCoder-Round#38
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1001
描述
- 給出四個三維坐標下的點, 判定是否為正方形.
分析
- 用向量的數量積來判定是否垂直, 再判斷長度.
- 我是在紙上畫出了A(3,2)=6 種情況然后暴力枚舉判斷是否為正方形. 組合數的意義表示在 2、3、4 三個點中有序選出兩個點和 1 相鄰.
- 我寫了一百多行的代碼, 看了看別人簡潔的代碼, 發現可以直接用STL的 next_permutation 來生成下一個排列, 把排列看做從左上角開始的順時針 (或逆時針) 四個點的編號, 就可以少打很多暴力枚舉.
- 尤其是在點數更多時這個辦法更有用.
- 然后就去看題解, 發現可以直接用三個點來判斷, 用向量法推出第四個點的坐標, 判定是否符合.
- 計算幾何的一些常用函數還是打成函數比較好, 可以降低代碼復雜度.
代碼
https://code.csdn.net/snippets/647464
#include <cstdio> using namespace std; typedef long long lli;struct Vector {lli x, y, z;Vector(lli x=0, lli y=0, lli z=0) : x(x), y(y), z(z) {}void init() {scanf("%lld%lld%lld", &x, &y, &z);} };Vector operator - (Vector A, Vector B) {return Vector(A.x-B.x, A.y-B.y, A.z-B.z); }lli Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y + A.z*B.z; } lli Length2(Vector A) { return Dot(A, A); }int main() {int T;scanf("%d", &T);Vector p1, p2, p3, p4;Vector u1, u2, u3, u4;Vector v1, v2, v3, v4;for(int kase = 1; kase <= T; kase++) {printf("Case #%d: ", kase);p1.init(); p2.init(); p3.init(); p4.init();u1 = p2-p1; v1 = p3-p1;u2 = p1-p2; v2 = p4-p2;u3 = p2-p4; v3 = p3-p4;u4 = p1-p3; v4 = p4-p3;if(Dot(u1, v1) == 0 && Dot(u2, v2) == 0 && Dot(u3, v3) == 0 && Dot(u4, v4) == 0) {if(Length2(u1) == Length2(v1) && Length2(u2) == Length2(v2) && Length2(u3) == Length2(v3) && Length2(u4) == Length2(v4)) puts("Yes");else puts("No");continue;}u1 = p2-p1; v1 = p4-p1;u2 = p1-p2; v2 = p3-p2;u3 = p2-p3; v3 = p4-p3;u4 = p1-p4; v4 = p3-p4;if(Dot(u1, v1) == 0 && Dot(u2, v2) == 0 && Dot(u3, v3) == 0 && Dot(u4, v4) == 0) {if(Length2(u1) == Length2(v1) && Length2(u2) == Length2(v2) && Length2(u3) == Length2(v3) && Length2(u4) == Length2(v4)) puts("Yes");else puts("No");continue;}u1 = p3-p1; v1 = p2-p1;u2 = p1-p3; v2 = p4-p3;u3 = p3-p4; v3 = p2-p4;u4 = p1-p2; v4 = p4-p2;if(Dot(u1, v1) == 0 && Dot(u2, v2) == 0 && Dot(u3, v3) == 0 && Dot(u4, v4) == 0) {if(Length2(u1) == Length2(v1) && Length2(u2) == Length2(v2) && Length2(u3) == Length2(v3) && Length2(u4) == Length2(v4)) puts("Yes");else puts("No");continue;}u1 = p3-p1; v1 = p4-p1;u2 = p1-p3; v2 = p2-p3;u3 = p3-p2; v3 = p4-p2;u4 = p1-p4; v4 = p2-p4;if(Dot(u1, v1) == 0 && Dot(u2, v2) == 0 && Dot(u3, v3) == 0 && Dot(u4, v4) == 0) {if(Length2(u1) == Length2(v1) && Length2(u2) == Length2(v2) && Length2(u3) == Length2(v3) && Length2(u4) == Length2(v4)) puts("Yes");else puts("No");continue;}u1 = p4-p1; v1 = p2-p1;u2 = p1-p4; v2 = p3-p4;u3 = p4-p3; v3 = p2-p3;u4 = p1-p2; v2 = p3-p2;if(Dot(u1, v1) == 0 && Dot(u2, v2) == 0 && Dot(u3, v3) == 0 && Dot(u4, v4) == 0) {if(Length2(u1) == Length2(v1) && Length2(u2) == Length2(v2) && Length2(u3) == Length2(v3) && Length2(u4) == Length2(v4)) puts("Yes");else puts("No");continue;}u1 = p4-p1; v1 = p3-p1;u2 = p1-p4; v2 = p2-p4;u3 = p3-p2; v3 = p4-p2;u4 = p1-p3; v2 = p2-p3;if(Dot(u1, v1) == 0 && Dot(u2, v2) == 0 && Dot(u3, v3) == 0 && Dot(u4, v4) == 0) {if(Length2(u1) == Length2(v1) && Length2(u2) == Length2(v2) && Length2(u3) == Length2(v3) && Length2(u4) == Length2(v4)) puts("Yes");else puts("No");continue;}puts("No");}return 0; }1002
描述
- 在數組 a中找出兩個數 ai, aj (i≠j), 使得 gcd(ai,aj) 取到最大值.
- 數組元素個數 n≤50000
分析
- 因為數組是給出的, 有不確定性, 所以放棄了找規律.
- 暴力拆解因數, 用 hash 表來存儲這個因數有沒有出現過. 如果這個因數出現過就更新答案, 否則標記為已出現.
- 枚舉因數肯定是 [1,n√] 之內的, 同時如果 i 是 x 的因數, xi 也是 x 的因數, 如果 xi 出現過, 那么就可以不再繼續枚舉了. 因為隨著 i 的增大, xi 會減小, 不會比現在答案更優.
- O(nn√)
- 還可以加一個優化, 就是把 a 數組 sort 后從大往小來判定. 這樣提前搜到答案的幾率或許更大一些.
代碼
https://code.csdn.net/snippets/647465
#include <cstdio> #include <cmath> #include <cstring> #include <algorithm> using namespace std; const int maxn = 100000 + 10;bool factor[maxn]; int c[maxn];int main() {int T;scanf("%d", &T);for(int kase = 1; kase <= T; kase++) {int n, ans = 1;scanf("%d", &n);memset(factor, 0, sizeof(factor));for(int i = 0; i < n; i++) scanf("%d", &c[i]);sort(c, c + n);for(int i = n-1; i >= 0; i--) {int x = c[i];for(int k = 1; k*k <= x; k++)if(x % k == 0) {if(ans >= x/k) break;if(factor[k]) ans = max(ans, k); else factor[k] = 1;if(k*k == x) continue;if(factor[x/k]) { ans = x/k; break; } else factor[x/k] = 1;} else if(ans >= x/k) break;}printf("Case #%d: %d\n", kase, ans);}return 0; }1003
待補
1004
描述
小F今天3歲生日,他爸爸送給他一套魔法積木作為生日禮物,積木一共包含n塊,編號從1到n,每塊積木都可以任意設置高度為整數h(1≤h≤m)。小F非常開心地玩起了積木,并按照以下步驟進行操作
(1) 首先,拿出編號為1的積木,任意設置高度為h1,放在第一行行首處。
(2) 當進行到第i步時(假設前i?1塊積木已經擺放成r行):拿出編號為i的積木,這時有兩種放法:
(I) 任意設置積木i的高度,然后把它放在r+1行行首(產生新的一行)
(II)從r行中任意選擇一行,任意設置積木i的高度hi使得hi不低于被選行最后一個積木高度,然后將積木i放在該行的最后
(3) n塊積木都使用后操作結束,形成了一個圖案
小F非常好奇,所有可能的操作下會形成多少種不同的圖案?對于兩種圖案,如果它們積木總行數相同,并且對應行總積木數相同,并且對應位置的編號高度都相同,兩種圖案便被視為相同。
分析
- 看題解、補題解.
- 動態規劃
- f[i] 表示前 i 個積木的圖案數.
- f[0]=1
- 接下來看由 f[j] 如何得到 f[i].
- 假設已經排好 j 個積木, 剩余 i?j 個積木, 為了不重復, 把它們全部放在新的一行. 假設 s[i] 表示 h[i]?h[i?1], 也就是差分. 規定 h[0]=1,h[i?j+1]=m. 則 ∑i?j+1i=1si=m?1, 求正整數解就可以限定 h 的取值在 [1,m] 之間. 正整數解的個數為 (i?j+1+m?1?1i?j+1?1)=(i?j+m?1i?j).
- 看題解還發現一個細節, 就是先拿出第一個積木來. 這樣可以保證該積木不會包含在那 j 個積木中, 只能在新的一行中. 保證不會出現重復.
總結
以上是生活随笔為你收集整理的BestCoder-Round#38的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: COGS-363-土地购买-斜率优化
- 下一篇: 算法学习-莫比乌斯反演