第一题:Allocation
题意:N个房子,第i个房子价格为Ai美元,用B美元最多买几个房子。
Limit:
1 ≤ T ≤ 100. 1 ≤ B ≤ 10^5. 1 ≤ Ai ≤ 1000, for all i. 1 ≤ N ≤ 10^5.
分析:按价格从小到大排序即可。
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<iostream> #include<set> #include<map> #include<stack> #include<queue> #include<vector> #include<sstream> typedef long long LL; const int INF = 0x3f3f3f3f; using namespace std; const int MAXN = 100000 + 10; const double eps = 1e-8; int dcmp(double a, double b){ if(fabs(a - b) < eps) return 0; return a < b ? -1 : 1; } int a[MAXN]; int main(){ int T; scanf("%d", &T); for(int Case = 1; Case <= T; ++Case){ int N, B; scanf("%d%d", &N, &B); for(int i = 0; i < N; ++i){ scanf("%d", &a[i]); } sort(a, a + N); int sum = 0; int cnt = 0; for(int i = 0; i < N; ++i){ if(sum + a[i] <= B){ sum += a[i]; ++cnt; } else break; } printf("Case #%d: %d\n", Case, cnt); } return 0; }
第二题:Plates
题意:有N堆盘子,每堆k个盘子,每个盘子有个beauty value。当拿某个盘子时,该盘子之上的盘子也会被拿起。问当拿P个盘子时,能获得最大的beauty value值。
Limit:
1 ≤ T ≤ 100. 1 ≤ K ≤ 30. 1 ≤ P ≤ N * K. The beauty values are between 1 and 100, inclusive. 1 ≤ N ≤ 50.
分析:dp[i][j]表示前i堆拿j个盘子能获得的最大beauty value值。
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<iostream> #include<set> #include<map> #include<stack> #include<queue> #include<vector> #include<sstream> typedef long long LL; const int INF = 0x3f3f3f3f; using namespace std; const int MAXN = 100000 + 10; const double eps = 1e-8; int dcmp(double a, double b){ if(fabs(a - b) < eps) return 0; return a < b ? -1 : 1; } int a[55][35]; int dp[55][1510]; //dp数组第二维比赛时开小了 int sum[55][35]; int main(){ int T; scanf("%d", &T); for(int Case = 1; Case <= T; ++Case){ int N, K, P; scanf("%d%d%d", &N, &K, &P); memset(sum, 0, sizeof sum); for(int i = 1; i <= N; ++i){ for(int j = 1; j <= K; ++j){ scanf("%d", &a[i][j]); sum[i][j] = sum[i][j - 1] + a[i][j]; } } memset(dp, 0, sizeof dp); for(int i = 1; i <= N; ++i){ for(int j = 0; j <= P; ++j){ dp[i][j] = max(dp[i][j], dp[i - 1][j]); for(int k = 1; k <= K && k <= j; ++k){ dp[i][j] = max(dp[i][j], dp[i - 1][j - k] + sum[i][k]); } } } printf("Case #%d: %d\n", Case, dp[N][P]); } return 0; }
优化一下,只开一维dp数组~
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<iostream> #include<set> #include<map> #include<stack> #include<queue> #include<vector> #include<sstream> typedef long long LL; const int INF = 0x3f3f3f3f; using namespace std; const int MAXN = 100000 + 10; const double eps = 1e-8; int dcmp(double a, double b){ if(fabs(a - b) < eps) return 0; return a < b ? -1 : 1; } int a[55][35]; int dp[1510]; int sum[55][35]; int main(){ int T; scanf("%d", &T); for(int Case = 1; Case <= T; ++Case){ int N, K, P; scanf("%d%d%d", &N, &K, &P); memset(sum, 0, sizeof sum); for(int i = 1; i <= N; ++i){ for(int j = 1; j <= K; ++j){ scanf("%d", &a[i][j]); sum[i][j] = sum[i][j - 1] + a[i][j]; } } memset(dp, 0, sizeof dp); for(int i = 1; i <= N; ++i){ for(int j = P; j >= 0; --j){ for(int k = 1; k <= K && k <= j; ++k){ dp[j] = max(dp[j], dp[j - k] + sum[i][k]); } } } printf("Case #%d: %d\n", Case, dp[P]); } return 0; }
第三题:Workout
题意:有N个session,每个session长达Mi分钟。定义diff为相邻session差值的最大值,要求增加至多K个session,使得diff最小,求最小的diff。(N个session的时长是严格递增的,要求增加k个session后,所有session时长也是严格递增的)
Limit:
1 ≤ T ≤ 100. For at most 10 test cases, 2 ≤ N ≤ 10^5. For all other test cases, 2 ≤ N ≤ 300. 1 ≤ Mi ≤ 10^9. Mi < Mi+1 for all i. 1 ≤ K ≤ 10^5.
分析:二分diff求右临界值即可。
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<iostream> #include<set> #include<map> #include<stack> #include<queue> #include<vector> #include<sstream> typedef long long LL; const int INF = 0x3f3f3f3f; using namespace std; const int MAXN = 100000 + 10; const double eps = 1e-8; int dcmp(double a, double b){ if(fabs(a - b) < eps) return 0; return a < b ? -1 : 1; } int a[MAXN]; int N, K; bool judge(int x){ int cnt = 0; for(int i = 2; i <= N; ++i){ if(a[i] - a[i - 1] > x){ int tmp = a[i - 1]; while(tmp + x < a[i]){ ++cnt; if(cnt > K) return false; tmp += x; } } } return true; } int main(){ int T; scanf("%d", &T); for(int Case = 1; Case <= T; ++Case){ scanf("%d%d", &N, &K); int diff = 0; for(int i = 1; i <= N; ++i){ scanf("%d", &a[i]); if(i > 1){ diff = max(diff, a[i] - a[i - 1]); } } int l = 1; int r = diff; while(l < r){ int mid = l + (r - l) / 2; if(judge(mid)) r = mid; else l = mid + 1; } printf("Case #%d: %d\n", Case, r); } return 0; }
第四题:Bundling
题意:有N个字符串,每个字符串只包含字母A~Z,要求把字符串按K个一组进行分组,每个字符串只能分到一个组中。分好后,每个组的score为该组所有字符串的最长公共前缀。问分组后每个组的score之和的最大值。
Limit:
1 ≤ T ≤ 100. 2 ≤ N ≤ 105. 2 ≤ K ≤ N. K divides N. Each of Pip's strings contain at least one character. Each string consists only of letters from A to Z. The total number of characters in Pip's strings across all test cases is at most 2 × 106.
分析:
(1)对于N个字符串中所有可能的前缀来说,假如某个前缀p存在于cnt个字符串中,则它对最终答案的贡献是cnt/K。累加所有的前缀贡献即可。
(2)计算每个前缀存在于多少个字符串中,用Trie树即可。
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<iostream> #include<set> #include<map> #include<stack> #include<queue> #include<vector> #include<sstream> typedef long long LL; const int INF = 0x3f3f3f3f; using namespace std; const int MAXN = 100000 + 10; const double eps = 1e-8; int dcmp(double a, double b){ if(fabs(a - b) < eps) return 0; return a < b ? -1 : 1; } struct TreeNode{ int val; TreeNode *nex[26]; TreeNode(){ val = 0; for(int i = 0; i < 26; ++i) nex[i] = NULL; } }; string s[MAXN]; void build(string x, TreeNode* root){ int len = x.size(); for(int i = 0; i < len; ++i){ int cur = x[i] - 'A'; if(root -> nex[cur] == NULL){ root -> nex[cur] = new TreeNode(); } root = root -> nex[cur]; ++root -> val; } } int bfs(TreeNode* root, int K){ int ans = 0; queue<TreeNode*> q; q.push(root); while(!q.empty()){ TreeNode *cur = q.front(); q.pop(); ans += cur -> val / K; for(int i = 0; i < 26; ++i){ if(cur -> nex[i] != NULL){ q.push(cur -> nex[i]); } } } return ans; } int main(){ int T; scanf("%d", &T); for(int Case = 1; Case <= T; ++Case){ int N, K; scanf("%d%d", &N, &K); TreeNode *root = new TreeNode(); for(int i = 0; i < N; ++i){ cin >> s[i]; build(s[i], root); } printf("Case #%d: %d\n", Case, bfs(root, K)); } return 0; }
也可以省掉bfs~
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<string> #include<iostream> #include<set> #include<map> #include<stack> #include<queue> #include<vector> #include<sstream> typedef long long LL; const int INF = 0x3f3f3f3f; using namespace std; const int MAXN = 100000 + 10; const double eps = 1e-8; int dcmp(double a, double b){ if(fabs(a - b) < eps) return 0; return a < b ? -1 : 1; } struct TreeNode{ int val; TreeNode *nex[26]; TreeNode(){ val = 0; for(int i = 0; i < 26; ++i) nex[i] = NULL; } }; string s[MAXN]; void build(string x, TreeNode* root, int K, int &ans){ int len = x.size(); for(int i = 0; i < len; ++i){ int cur = x[i] - 'A'; if(root -> nex[cur] == NULL){ root -> nex[cur] = new TreeNode(); } root = root -> nex[cur]; ++root -> val; if(root -> val == K){ ++ans; root -> val = 0; } } } int main(){ int T; scanf("%d", &T); for(int Case = 1; Case <= T; ++Case){ int N, K; scanf("%d%d", &N, &K); TreeNode *root = new TreeNode(); int ans = 0; for(int i = 0; i < N; ++i){ cin >> s[i]; build(s[i], root, K, ans); } printf("Case #%d: %d\n", Case, ans); } return 0; }
来源:https://www.cnblogs.com/tyty-Somnuspoppy/p/12546794.html