http://discuss.acmcoder.com/topic/58db8e2ebb0f44ba0e94e670
上面是完整的題目,下面一下我自己的想法。
http://discuss.acmcoder.com/topic/58db8e2ebb0f44ba0e94e670
官方題解。
這次做的比較菜,就做出來第二題,1和3都沒搞出來。
1. 第一題,首先知道數一個數階乘末尾0的個數,由於5*2 = 10,5比2多,所以就變成數因子5的個數,5的數法,需要找規律,首先每五個數有一個因子5,然后接下來壓縮后,每5個數,還有一個5,不斷的遞歸調用,即可。同理,數其他的質因子都是這樣吧。
我做的時候,老是以為有什么規律,默認為就是數學題么,肯定有規律的,然后沒接出來。
有了快速數5的個數的方法以后,那么解法就顯而易見了,就是二分。而且題目,也提醒單調的性質,就差直接提醒你用二分了,然后就是對可能的答案進行二分,多了往左走,少了往右走。很容易分析最大可能的答案是最大的數乘以5.然后二分。
總結出一個套路:有單調的性質,或者有非遞減的性質之類的,立馬要想到二分,有些二分可能不明顯,如對答案二分等,需要仔細分析。同時,注意二分的幾種寫法,滿足要求最小的,滿足要求最大的,或者唯一的,寫法都不太一樣,注意。

1 #include <bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const ll inf = 5e8; 5 6 ll work(ll t) { 7 ll res = 0; 8 while(t > 1) { 9 res += t / 5; 10 t /= 5; 11 } 12 return res; 13 } 14 void solve() { 15 int x; 16 for (x = 1; x <= 50; x++) { 17 ll left = 5, right = inf; 18 while(left < right) { 19 ll mid = (left + right) / 2; 20 ll t = work(mid); 21 if(t < x) left = mid + 1; 22 else right = mid; 23 } 24 if(work(left) == x) cout << left << endl; 25 else cout << -1 << endl; 26 } 27 } 28 29 int main() { 30 freopen("test.in", "r", stdin); 31 freopen("test.out", "w", stdout); 32 ios::sync_with_stdio(0); 33 cin.tie(0); cout.tie(0); 34 solve(); 35 return 0; 36 }
2. 第二題,顯然是一棵樹,然后固定樹的層次結構,對每一個節點,需要找到兒子里面的最長路徑,以及該節點外的最長路徑,發現不好計算,然后轉化為依次切割每一條邊,分別這個邊兩邊的最長路徑。看答案,我是真的把邊刪掉,其實只要簡單設置根節點的父節點為相鄰節點即可,真是個好方法。然后這個題數據范圍很小,應該能跑出來,每次都是O(n)的,所以很容易的就ac了。

1 /* 2 ID: y1197771 3 PROG: test 4 LANG: C++ 5 */ 6 #include<bits/stdc++.h> 7 #define pb push_back 8 #define FOR(i, n) for (int i = 0; i < (int)n; ++i) 9 #define dbg(x) cout << #x << " at line " << __LINE__ << " is: " << x << endl 10 typedef long long ll; 11 using namespace std; 12 typedef pair<int, int> pii; 13 const int maxn = 2e2 + 10; 14 int e[maxn][maxn]; 15 int n; 16 vector<pii> a; 17 int ans; 18 int work(int u, int p) { 19 int x, y; 20 x = y = 0; 21 for (int i = 1; i <= n; i++) { 22 if(e[u][i] && i != p) { 23 int t = work(i, u); 24 if(t > y) y = t; 25 if(y > x) swap(x, y); 26 } 27 } 28 ans = max(ans, x + y + 1); 29 return x + 1; 30 } 31 void solve() { 32 while(cin >> n) { 33 memset(e, 0, sizeof e); 34 int x, y; 35 a.clear(); 36 for (int i = 0; i < n - 1; i++) { 37 cin >> x >> y;//cout << x << " " << y << endl; 38 e[x][y] = 1; 39 e[y][x] = 1; 40 a.pb({x, y}); 41 42 } 43 44 int res = 0; 45 46 for (int i = 0; i < n - 1; i++) { 47 x = a[i].first, y = a[i].second; 48 e[x][y] = e[y][x] = 0; 49 int t1, t2; 50 t1 = t2 = 0; 51 ans = 0; 52 work(x, 0); 53 t1 = max(0, ans - 1); 54 ans = 0; 55 work(y, 0); 56 t2 = max(0, ans - 1); 57 res = max(res, t1 * t2); 58 e[x][y] = e[y][x] = 1; 59 } 60 cout << res << endl; 61 } 62 } 63 int main() { 64 freopen("test.in", "r", stdin); 65 //freopen("test.out", "w", stdout); 66 ios::sync_with_stdio(0); 67 cin.tie(0); cout.tie(0); 68 solve(); 69 return 0; 70 }
3. 第三題,讀完題意,沒啥想法,我的想法是對每一個區間進行求解,每個區間必須是匹配的,也就是完整的,然后第一個位置就是‘(’,然后一次枚舉‘)’可以放的位置,進行遞歸求解,復雜度太高。直接tle。
沒想法,只好看題解答案。
居然是轉化成1,-1的形式進行處理,太巧秒了!(我就想到上次有一個01的序列,求最長的區間,這個區間滿足0和1的個數相等,也是處理成-1和1的形式,真是夠巧妙的。)處理成1,-1的形式,那么括號匹配的情況就很顯然了,就是前面和為0,而且合法的情況必然是前面的和大於等於0的,這個也很關鍵,下面考慮怎么縮減問題規模,也就是怎么轉移(通常的dp套路,縮減問題規模,轉化為規模較小的子問題,而分出來的那一小部分很好計算)。然后就是第k個位置,可能的合法的情況就是0-k,0代表前面完全匹配,k代表前面的都是左括號,這樣,前面就不會出現右括號不匹配的情況。
特別注意n*=2,然后考慮還會有一些非法的情況出現,比如偶數位置上,是不可能達到0的,設置這些狀態為一個很小的數,使得不干擾最后的結果。
真是個好題!

1 /* 2 ID: y1197771 3 PROG: test 4 LANG: C++ 5 */ 6 #include<bits/stdc++.h> 7 #define pb push_back 8 #define FOR(i, n) for (int i = 0; i < (int)n; ++i) 9 #define dbg(x) cout << #x << " at line " << __LINE__ << " is: " << x << endl 10 typedef long long ll; 11 using namespace std; 12 typedef pair<int, int> pii; 13 const int maxn = 1e3 + 10; 14 const int inf = -1e9; 15 int dp[2010][2010]; 16 int n; 17 int a1[2010], a2[2010]; 18 void solve() { 19 cin >> n; 20 for (int i = 1; i <= 2 * n; i++) { 21 cin >> a1[i]; 22 } 23 for (int i = 1; i <= 2 * n; i++) { 24 cin >> a2[i]; 25 } 26 for (int i = 1; i <= n * 2; i++) 27 dp[0][i] = inf; 28 for (int i = 1; i <= n * 2; i++) { 29 for (int j = 0; j <= i; j++) { 30 if(j == 0) { 31 dp[i][j] = dp[i - 1][j + 1] + a2[i]; 32 } else { 33 dp[i][j] = max(dp[i - 1][j + 1] + a2[i], dp[i - 1][j - 1] + a1[i]); 34 } 35 } 36 } 37 cout << dp[n * 2][0] << endl; 38 } 39 int main() { 40 freopen("test.in", "r", stdin); 41 //freopen("test.out", "w", stdout); 42 ios::sync_with_stdio(0); 43 cin.tie(0); cout.tie(0); 44 solve(); 45 return 0; 46 }
做完題目,只有多總結,分析原因,尤其是自己當初做的時候是怎么想的,有沒有計算復雜度,考慮可行性, 不行的話,有沒有pass掉, 然后為什么沒有想出題解的這樣的方式,這才是最重要的,這樣提高才是最快的,否則,跟沒有做一樣!