題意:
無向圖,修公路,第i個城市的值是a[i],第j個城市的值是a[j],在他們之間修公路花費gcd(a[i] , a[j]),求修公路連接所有n個城市的最小花費
思路:(MST)
最小生成樹問題,對kruskal進行變形,但由於這題范圍太大,不能暴力枚舉所有任意兩個數的最大公約數,所以要考慮素數分布,然后我們再來看題面:n個點的最小生成樹,邊權是gcd(a[i] , a[j]),
當n很大時(差不多大於1000時),就肯定存在素數,邊權就都是1,得出的最小生成樹值就是n - 1。(結論直接用),在n小於1000時正常跑kruskal
另外還有一種情況,就是L = R時,說明邊權都是L,得出的最小生成樹就是(n - 1) * L,並且這里注意開long long
由於平常的kruskal算法都是直接給了說是有m條邊,但這個題沒給,所以不知道總邊數,那么可以開一個idx表示總邊數。
//本題示例
for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) { int w = gcd(a[i], a[j]); edge[idx ++ ] = {i , j , w}; }
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <algorithm> 5 #include <cmath> 6 #include <queue> 7 #include <vector> 8 #include <map> 9 #include <set> 10 11 #define x first 12 #define y second 13 14 using namespace std; 15 16 typedef long long LL; 17 typedef pair<int, int>PII; 18 19 const int N = 100010; 20 21 int n, L, R, a[200001]; 22 int idx; 23 int p[N]; 24 struct Edge 25 { 26 int a, b, w; 27 bool operator < (const Edge& t) const 28 { 29 return w < t.w; 30 } 31 }edge[N]; 32 33 unsigned long long seed; 34 unsigned long long xorshift64() 35 { 36 unsigned long long x = seed; 37 x ^= x << 13; 38 x ^= x >> 7; 39 x ^= x << 17; 40 return seed = x; 41 } 42 int gen() 43 { 44 return xorshift64() % (R - L + 1) + L; 45 } 46 47 int gcd(int a, int b) 48 { 49 int c = a % b; 50 while (c) 51 { 52 a = b; 53 b = c; 54 c = a % b; 55 } 56 return b; 57 } 58 59 int find(int x) 60 { 61 if (p[x] != x) p[x] = find(p[x]); 62 return p[x]; 63 } 64 65 LL kruskal() 66 { 67 sort(edge + 1, edge + 1 + idx); 68 LL res = 0, cnt = 0; 69 70 for (int i = 1; i <= idx; i++) 71 { 72 int a = edge[i].a, b = edge[i].b, w = edge[i].w; 73 74 a = find(a), b = find(b); 75 if (a != b) 76 { 77 p[a] = b; 78 res += w; 79 cnt++; 80 } 81 if (cnt == n - 1) break; 82 } 83 return res; 84 } 85 86 int main() 87 { 88 scanf("%d%d%d%llu", &n, &L, &R, &seed); 89 for (int i = 1; i <= n; i++) a[i] = gen(); 90 91 if (L == R) 92 { 93 cout << (LL)(n - 1) * L << endl;//化為long long,不然有個點過不了 94 return 0; 95 } 96 if (n >= 1000) 97 { 98 cout << n - 1 << endl; 99 return 0; 100 } 101 //n < 1000
102
103 for (int i = 1; i <= n; i++) p[i] = i; 104 105 for (int i = 1; i <= n; i++) 106 for (int j = 1; j <= n; j++) 107 { 108 int w = gcd(a[i], a[j]); 109 edge[idx ++ ] = {i , j , w}; 110 } 111 112 cout << kruskal() << endl; 113 114 return 0; 115 }
題意:
二維空間里放了n個盒子,有水平往左和豎直往下兩種重力,求重力作用之后形成的輪廓周長。
思路:(模擬)(思維)
首先每次輸入一個方塊,周長就加4,然后判斷平移之后挨着別的方塊,這里拿向左平移舉例子,當輸入一個新的方塊后,當這一行原來有別的方塊時,平移之后肯定會左右挨着,這時就去掉兩條邊的
長度:
另外的情況就是當輸入一個新方塊后,向左平移之后上下挨着別的方塊:
因為上下挨着兩種情況對稱,考慮下面挨着的情況,那么上面挨着的情況就照葫蘆畫瓢就可以了,那么這種情況一定要想清楚,假如記這一行是x[xx],下面一行是x[xx - 1],判斷的是新輸入的這個方塊是否
有下面挨着的方塊,假如上面一行右邊那個方塊是新輸入的方塊,那么很顯然平移之后它下面沒有挨着的方塊,而假如上面一行左邊那個方塊是新輸入的方塊,那么它就有下面挨着的方塊,我們分析一下,
可以發現當下面一行的方塊數大於等於這一行的方塊數時,新輸入的這個方塊就有下面挨着的方塊,那么答案就去掉兩條邊的長度。
上面挨着的情況同理。
上面的圖的情況是新輸入的方塊沒有挨着的
那么新輸入的方塊下面挨着別的方塊的情況再舉個例子:
然后向下平移的情況就對着向左平移的情況照葫蘆畫瓢就完了
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <algorithm> 5 #include <cmath> 6 #include <queue> 7 #include <vector> 8 #include <map> 9 #include <set> 10 11 #define x first 12 #define y second 13 14 using namespace std; 15 16 typedef long long LL; 17 typedef pair<int, int>PII; 18 19 const int N = 200010; 20 21 int n; 22 int x[N], y[N]; 23 LL res1, res2; 24 25 int main() 26 { 27 cin >> n; 28 for (int i = 1; i <= n; i++) 29 { 30 int xx, yy; 31 cin >> xx >> yy; 32 res1 += 4, res2 += 4; 33 34 if (x[xx]) res1 -= 2; 35 x[xx] ++; 36 if (x[xx - 1] >= x[xx]) res1 -= 2; 37 if (x[xx + 1] >= x[xx]) res1 -= 2; 38 39 40 if (y[yy]) res2 -= 2; 41 y[yy] ++; 42 if (y[yy - 1] >= y[yy]) res2 -= 2; 43 if (y[yy + 1] >= y[yy]) res2 -= 2; 44 45 46 cout << res1 << ' ' << res2 << endl; 47 } 48 49 return 0; 50 }
題意:
一個人去打怪獸,當他打過這個怪獸之后,會損失一定的生命值和疲勞值,並獲得一定數量的金幣,如果生命值減為零了,人就死了,而如果疲勞值減為零了,就相應的從生命值里扣,問保證這個人活着的前提下,能獲得的金幣的最大值是多少。
思路:(dp)
首先考慮結構體排序用貪心來做,但在分析的過程中我們就發現要考慮的條件實在是太多了,所以基本不太可能用貪心了。然后就考慮dp,發現dp是可以的,可以看出這個題是01背包的變形,即遇到一個怪獸,你是打還是不打,對應01背包中一個物品選還是不選的情況。
由於這個題是三維的,所以如果不優化的話只能過不到百分之四十的樣例,所以我們最后優化掉 i 這一維空間就可以了,注意關鍵點就是 j 這一維,就是生命值這一維,循環時是大於h[i]的(H到h[i]),
如果用集合角度考慮這個dp問題的話(閆氏dp分析法),即為這個人在生命值大於0時,可以獲得的最大金幣數。
最后注意開 long long
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <algorithm> 5 #include <cmath> 6 #include <queue> 7 #include <vector> 8 #include <map> 9 #include <set> 10 11 #define x first 12 #define y second 13 14 using namespace std; 15 16 typedef long long LL; 17 typedef pair<int, int>PII; 18 19 const int N = 1010; 20 21 LL n, H, S; 22 LL h[N], s[N], w[N]; 23 LL f[310][310]; 24 25 int main() 26 { 27 cin >> n >> H >> S; 28 29 for (int i = 1; i <= n; i++) cin >> h[i] >> s[i] >> w[i]; 30 31 LL res = 0; 32 for (int i = 1; i <= n; i++) 33 for (int j = H; j > h[i]; j--) 34 { 35 for (int k = S; k >= 0; k--) 36 { 37 if (k >= s[i]) f[j][k] = max(f[j][k], f[j - h[i]][k - s[i]] + w[i]); 38 else 39 { 40 if (j - h[i] - (s[i] - k) > 0) 41 f[j][k] = max(f[j][k], f[j - h[i] - (s[i] - k)][0] + w[i]); 42 43 } 44 45 res = max(res, f[j][k]); 46 } 47 } 48 49 cout << res << endl; 50 51 return 0; 52 }
題意:
給定 一個0/1矩陣C ,構造兩個矩陣 A , B ,其中 1 形成了完整的不分散的一塊四連通塊,並且對於 C 中所有位置,若是 1,則 A , B 對應位置必須都是 1,否則 A , B 之中必須有一個這個位置為 0 。 保證C陣的邊框都是0 。
思路:(思維)
這題真的讀懂題意是關鍵,因為這題說C的邊界都是0,所以我們可以讓A的最左邊一列都是 1 ,B的最右邊一列都是 1 ,然后行分奇偶,假如A的奇數行染1 , B的偶數行染1,那么這樣一定保證所有的1都是連通的。
注意的點就是存矩陣c的時候用char ,不要用int , 因為存的是某一個點的東西
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <algorithm> 5 #include <cmath> 6 #include <queue> 7 #include <vector> 8 #include <map> 9 #include <set> 10 11 #define x first 12 #define y second 13 14 using namespace std; 15 16 typedef long long LL; 17 typedef pair<int, int>PII; 18 19 const int N = 510; 20 21 int n, m; 22 char c[N][N]; 23 24 int main() 25 { 26 cin >> n >> m; 27 for (int i = 1; i <= n; i++) 28 for (int j = 1; j <= m; j++) 29 cin >> c[i][j]; 30 31 for (int i = 1; i <= n; i++)//A矩陣 32 { 33 for (int j = 1; j <= m; j++) 34 if (i == 1 || (j % 2 == 1 && i != n)) cout << 1; 35 else cout << c[i][j]; 36 37 cout << endl; 38 } 39 40 for (int i = 1; i <= n; i++)//B矩陣 41 { 42 for (int j = 1; j <= m; j++) 43 if (i == n || (j % 2 == 0 && i != 1)) cout << 1; 44 else cout << c[i][j]; 45 46 cout << endl; 47 } 48 49 return 0; 50 }