情况 时间:2024年7月1日 星期一 17:15 完成情况:
题解 A. Alice and Books 题意 将数分成两堆,选取每堆”最大数字”的书读。
思路 读题类题目,认真读了快十分钟做出来···,都以为是最大页数。最大数字必定看,因此找出最小到第二大数字中最大页数的书。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const int N = 101 ;int main () { int t; cin >> t; while (t--){ int n; int c[N]; cin >> n; for (int i = 0 ;i<n;i++) cin >> c[i]; sort (c, c+n-1 ); int ans = 0 ; ans = c[n - 1 ] + c[n - 2 ]; cout << ans << endl; } return 0 ; }
B. New Bakery 题意 卖东西,分为正常价格a和活动价格b,第k个活动价格为b−i+1。问最大的利润。
思路 初中函数题目,写出二次方程方程式: $w=-(0.5) * k^2 + (0.5 - a + b) * k + n * a$ 当k=(0.5-a+b)时候最大。 直接在周边几个整数比较大小。 分情况讨论: 先看是否b - n + 1 > a,也就是说活动价永远比正常价格好。如果是,所有物品都用活动价卖出,k=n; 如果不是这样:
最大值的k小于等于0,k=0;
最大值的k大于0,k取(0.5-a+b),代入算出周边整数值最大情况。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <algorithm> #include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include <sstream> #include <iomanip> using namespace std; typedef long long LL;typedef pair<int , int > PII; const int N = 100000 ; LL func (LL a, LL b, LL n, LL k) { return -(0.5 ) * k * k + (0.5 - a + b) * k + n * a; } int main () { int t; cin >> t; while (t--) { LL n, a, b; cin >> n >> a >> b; if (0.5 - a + b > 0 && b - n + 1 < a) { LL ans = max (func (a, b, n, (0.5 - a + b)), func (a, b, n, (1.5 - a + b))); ans = max (ans, (LL)func (a, b, n, (-0.5 - a + b))); cout << ans << endl; } else if (b - n + 1 >= a) { cout << func (a, b, n, n) << endl; } else { cout << func (a, b, n, 0 ) << endl; } } return 0 ; }
问题 这题耽误太多时间(40分钟)的原因就是第一个if少了个b-n+1<a,导致都用第一个算,有一个样例一直过大。要注意if条件对应的情况,划分要清楚。
C. Manhattan Permutations 题意 一种算法,交换1,2,3,4,5···的顺序从而使|p1−1|+|p2−2|+…+|pn−n|=一个值k。如果可行,输出Yes和交换后的顺序。如果不可行,输出No。
思路 先讨论:
k为奇数永远不可能,直接no
k为偶数:
计算此时能表示的最大值(数学推等差数列) 如果k大了,no 如果没有大,进入下一阶段: 在原封不动的情况下,交换一次增长的值是2*交换两者下表的差。 因此直接依据此贪心,每个位置最多交换一次,用双指针从开头和结尾向中间遍历,进行交换,并更新到k还剩多少。 直到交换两者增长的值大于现在的需求了。改为移动一个指针,获取最后一次交换。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 #include <algorithm> #include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include <sstream> #include <iomanip> using namespace std;typedef long long LL;typedef pair<int , int > PII;const int N = 200001 ;int main () { int t; cin >> t; while (t--) { LL n, k; cin >> n >> k; LL max = 0 ; if (n % 2 == 0 ) { max = (n * 0.5 ) * (n * 0.5 ) * 2 ; } else { max = (n + 1 ) * 0.5 * ((n + 1 ) * 0.5 - 1 ) * 2 ; } if (k % 2 == 1 ) { cout << "No" << endl; } else if (k > max) { cout << "No" << endl; } else { LL need = 0.5 * k; cout << "Yes" << endl; int r = n, l = 1 ; int ans[N] = {0 }; for (int i = 1 ; i <= n; ++i) { ans[i] = i; } while (r - l <= need) { int t =ans[l]; ans[l] = ans[r]; ans[r] = t; need =need- r + l; l++; r--; if (need == 0 ){ break ; } } while (need != 0 ){ l++; if (r - l == need){ swap (ans[l], ans[r]); need -= r - l;} } for (int i = 1 ; i <= n; ++i) { cout << ans[i] << " " ; } cout << endl; } } return 0 ; }
问题 这个过程耗时最大的就是第一个while一直输出不出来,直到后来在循环中加了一个break检测:
1 2 3 if (need == 0 ){ break ; }
也就是一阶段就成功的情况没考虑,导致第一个用例就过不了。后面也是极限救场了,凭感觉写的贪心哭着也要写完。
D. Elections 赛后补一题。1600分。赛中也没来得及开。用时1小时,还挺满意的做出来了。
题意 有选举者按序号排序,每个选举者有固定票(粉丝)和犹豫票。犹豫者刚开始就有,会把票给序号最小(最左)者;排除一个选举者,他的粉丝全部变成犹豫票。 问你:如何排除最小数量的选举者,从而赢得选举?
思路 全是贪心,做烂了。 先遍历一遍,找到最大值所在处max。顺便搞个前缀和数组。 然后遍历选举者,分情况讨论:
当前位置是max:
第一位fans[1]加上犹豫者,fans[1]+c小于max,则一个也不用去掉,输出0;
第一位就是最大值,也输出0,不用去掉
fans[1]+c大于max,遍历maxwhere(max的位置,也就是现在看的位置)之前的选举者
遍历过程中若发现c + sum[j] < max,遍历结束,即去掉j之前的选举者,输出j-1
遍历到头,那就输出maxwhere-1,把之前的都去掉。
当前位置不是max,前面肯定都得去掉
如果max的位置在这之前,那去掉了直接变成新的max,输出当前位置之前,i-1;
否则,在这之后,要考虑用不用把max去了,计算c + sum[i] >= max
是,则证明不用去,输出i-1
否,则证明还是得把max去掉,输出i
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 #include <algorithm> #include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include <sstream> #include <iomanip> using namespace std;typedef long long LL;typedef pair<int , int > PII;const int N = 200001 ;LL fans[N]; LL c; int main () { int t; cin >> t; while (t--) { int n; LL sum[N] = {0 }; cin >> n >> c; for (int i = 1 ; i <= n; ++i) { cin >> fans[i]; sum[i] = sum[i - 1 ] + fans[i]; } LL max = fans[1 ]; int maxwhere = 1 ; for (int i = 1 ; i <= n; ++i) { if (max < fans[i]) { max = fans[i]; maxwhere = i; } } for (int i = 1 ; i <= n; ++i) { if (i == maxwhere) { if (c + fans[1 ] < max || maxwhere == 1 ) { cout << 0 << " " ; } else { int yes = 0 ; for (int j = 1 ; j < maxwhere; j++) { if (c + sum[j] >= max) { continue ; } else { cout << j - 1 << " " ; yes = 1 ; } } if (yes != 1 ) { cout << maxwhere - 1 << " " ; } } } else { if (maxwhere < i) { cout << i - 1 << " " ; } else { if (c + sum[i] >= max) { cout << i - 1 << " " ; } else cout << i << " " ; } } } cout << endl; } return 0 ; }
问题 令人感慨做的还挺丝滑的,不过就是忘开LL导致wa了一次,看了测试用例情况。要是比赛遇到不知道能不能反映过来···