public: voidset(vector<int>& xs){ int sum = 0; pre_sum.push_back(0); for (int x : xs) { sum += x; pre_sum.push_back(sum); nums.push_back(x); } } // 使用倍增算法查询 intquery_double(int t){ int sum = 0, l = 1, k = 0; while (l > 0) { if (k + l < pre_sum.size() && sum + pre_sum[k + l] - pre_sum[k] <= t) { sum += (pre_sum[k + l] - pre_sum[k]); l *= 2; k += l; } else { l /= 2; } } return k - 1; } // 通过二分查找查询 intquery_binary_search(int t){ auto loc = upper_bound(pre_sum.begin(), pre_sum.end(), t); return loc - pre_sum.begin() - 2; } };
// 生成一个随机数组 for (int i = 0; i < 100000; i++) { nums.push_back(distr(eng)); } s.set(nums);
// 1.t随机分布 // 生成测试数组 vector<int> test_list; int sum = accumulate(nums.begin(), nums.end(), 0); distr = uniform_int_distribution<int>(0, sum); for (int i = 0; i < 100000; i++) { test_list.push_back(distr(eng)); }
// 用两种方法分别测试 clock_t start, end; start = clock(); for (int t : test_list) { s.query_binary_search(t); } end = clock(); cout << "time of using binary search: " << double(end - start) / CLOCKS_PER_SEC << endl; start = clock(); for (int t : test_list) { s.query_double(t); } end = clock(); cout << "time of using times increase: " << double(end - start) / CLOCKS_PER_SEC << endl;
// 2. t比较小 // 生成测试数组 test_list.clear(); distr = uniform_int_distribution<int>(0, sum / 10000); for (int i = 0; i < 100000; i++) { test_list.push_back(distr(eng)); }
// 用两种方法分别测试 start = clock(); for (int t : test_list) { s.query_binary_search(t); } end = clock(); cout << "time of using binary search: " << double(end - start) / CLOCKS_PER_SEC << endl; start = clock(); for (int t : test_list) { s.query_double(t); } end = clock(); cout << "time of using times increase: " << double(end - start) / CLOCKS_PER_SEC << endl; }
下面是测试结果
1 2 3 4 5 6
// t随机分布 time of using binary search: 0.019 time of using times increase: 0.02 // t值比较小 time of using binary search: 0.011 time of using times increase: 0.006
#include<stdio.h> #include<algorithm> #include<cmath> #include<iostream> #define LL long long usingnamespace std; int A[500000]; int B[500000]; int C[500000];
voidmerge(int begin, int mid, int end){ int l = begin, r = mid, pt = begin; while (l < mid && r < end) { if (B[l] < B[r]) { C[pt++] = B[l++]; } else { C[pt++] = B[r++]; } } while (l < mid) { C[pt++] = B[l++]; } while (r < end) { C[pt++] = B[r++]; } } // 将数组B[mid, end)排序,后将B[begin, mid)与B[mid, end)归并 voidsingle_sort(int begin, int mid, int end){ sort(B + mid, B + end); merge(begin, mid, end); } // 计算排好序后的数组C在[begin, end)范围的校验值 LL cal(int begin, int end, int m){ int l = begin, r = end - 1; LL ret = 0; while (l < r && m > 0) { ret += ((LL)C[r] - C[l]) * ((LL)C[r] - C[l]); m--, l++, r--; } return ret; } intforward(int n, int begin, int m, LL t){ int l = 1, p = begin; LL sum = 0; while (l > 0) { if (p + l <= n) { for (int i = p; i < p + l; i++) B[i] = A[i]; single_sort(begin, p, p + l); sum = cal(begin, p + l, m); if (sum <= t) { p += l; l *= 2; for (int i = begin; i < p; i++) B[i] = C[i]; } else { l /= 2; } } else { l /= 2; } } if (sum == 0) p = n; return p; } intpartition(int n, int m, LL t){ int p = 0, ret = 0; while (p < n) { p = forward(n, p, m, t); ret++; } return ret; } intmain(){ int k; scanf("%d", &k); for (int i = 0; i < k; i++) { int n, m; LL t; scanf("%d %d %lld", &n, &m, &t); for (int i = 0; i < n; i++) { scanf("%d", &A[i]); } printf("%d\n", partition(n, m, t)); } }