C.Increase and Copy #枚举
题意
最初你有仅包含一个数字1的数组a,一次操作中可对该数组进行两类操作:
- 从数组中选择一个元素,将该元素+1;
- 从数组中选择一个元素,复制该元素放到原数组末端。
你需要在尽可能少的操作次数下,使得该数组所有元素值之和不小于n(n≤1e9),现要你求出最少操作次数
分析
显然,操作过程中,一定是先对最初元素不断自增,直到某个值后,再复制这个元素,即先进行第一类操作再进行第二类,这样能够保证操作次数尽可能少。
那么我们应该将最初元素加到多少才复制呢?我们可以枚举该元素可以增加至i,那么消耗次数为i−1,那么接下来复制次数即为⌈in−i⌉,故总消耗次数为i−1+⌈in−i⌉。枚举i,找到i−1+⌈in−i⌉的最小值即可。另外,我们无需从1枚举到n,枚举到n即可。
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
| #include <string> #include <cstring> #include <cstdio> #include <iostream> #include <stack> #include <cmath> #include <queue> #include <map> #include <vector> #include <deque> #include <algorithm> #include <unordered_map> using namespace std; typedef long long ll; const int MAXN = 15; int q, n; int main(){ scanf("%d", &q); while(q--){ scanf("%d", &n); int mymin = 0x3f3f3f3f; for(int i = 1; i * i <= n; i++){ int sum = (i - 1) + (n - i) / i + ((n - i) % i != 0); mymin = min(mymin, sum); } printf("%d\n", mymin); } return 0; }
|
由官方题解思路,因为所求最值应该在n的附近,我们枚举[⌊n⌋+5,⌊n⌋−5]找最值,就能达到O(1)复杂度了。
D. Non-zero Segments #前缀和 #哈希表
题意
给定长为n、包含正整数、也会包含负整数、但一定不包含0的数组a,你需要在这个数组中某些位置插入任意值,保证该数组任意区间值之和等于0,现要你求出最少插入元素数量。
分析
设该数组前缀和sumi,我们知道,**某个区间[l,r]的值之和为0,那么就意味着sumr与suml是相等的。**于是,我们便可通过哈希表去记录某个前缀和是否出现过,一旦出现过,假设从左到右遍历到i,发现当前的前缀和sumi,在之前出现过,说明这一中间区间的权值之和一定为0,那么按照题目要求,我们将某个值插入到i的前面,使得这一中间区间的权值之和不为0的同时,保证不会与后面区间相加为0(实际插入值无需真的确定下来),此时答案加1(当然,这只是个假想的插入操作,无需真的模拟,只需要将当前前缀和置为0,从i开始重新计sum即可)。别忘了,每次迭代的过程中,要记录当前前缀和到哈希表中。另外预处理时,应将前缀和为0记录到哈希表,因为有可能相邻两元素恰好为相反数。
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
| #include <string> #include <cstring> #include <cstdio> #include <iostream> #include <stack> #include <cmath> #include <queue> #include <map> #include <vector> #include <deque> #include <algorithm> #include <unordered_map> using namespace std; typedef long long ll; const int MAXN = 2e5+5; unordered_map<ll, int> mymap; int main(){ int n, ans = 0; scanf("%d", &n); ll sum = 0, cur; mymap[0] = 1; for(int i = 1; i <= n; i++){ scanf("%lld", &cur); sum += cur; if(mymap[sum] > 0){ mymap.clear(); mymap[0] = 1; sum = cur; ans++; } mymap[sum]++; } printf("%d\n", ans); return 0; }
|