1 条题解
-
0
多好的一道思维题!
蒟蒻觉得大佬们双指针贪心部分讲得有些简略,故写一篇题解来具体说说自己的想法。
首先,我们要发现一个重要的性质:记最终的答案为 ,那么 一定整除 。因为无论怎么操作序列的和都不变,且最后必须保证 是所有 的公约数。
那么,我们记 ,则 一定是 的因子。那就需要枚举 的因子,合法的最大因子就是 。
接下来就是判断是否合法。当考察因子 时,考虑记录每个 ,并将它们从小到大排序,接着进行双指针扫描,贪心地计算所需操作次数 ,若 则合法。记左指针为 ,右指针为 ,具体贪心实现如下:
-
若 ,那么操作 次 就可以都变成 , 加上 ,两个指针都向中间靠 个坐标。
-
若 ,那么钦定操作 次使得 变成 ,则 变成 , 加上 ,左指针向中间靠 个坐标。
-
若 ,那么钦定操作 次使得 变成 ,相当于变成 ,则 变成 , 加上 ,右指针向中间靠 个坐标。
如果你对后两个操作有疑问,如“为什么要这样钦定”,请代入前提条件“已经将 从小到大排序”。
那么本题就完成了,时间复杂度是 。但实际上肯定要比这个快,因为 是检查因数时排序的复杂度。
#include <bits/stdc++.h> #define i64 long long const int N = 505; using namespace std; int n, k, a[N]; i64 sum, ans, b[N]; bool chk(i64 x) { for(int i = 1; i <= n; i++) b[i] = 1ll * a[i] % x; sort(b + 1, b + n + 1); int l = 1, r = n; i64 cnt = 0; while(l <= r) { if(b[l] + b[r] == x) cnt += b[l], l++, r--; else if(b[l] + b[r] < x) cnt += b[l], b[r] += b[l], l++; else if(b[l] + b[r] > x) cnt += x - b[r], b[l] -= (x - b[r]), r--; if(cnt > k) return false; } return cnt <= k; } int main(){ scanf("%d %d", &n, &k); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); sum += a[i]; } for(i64 i = 1; i * i <= sum; i++) { if(sum % i == 0) { if(i > ans && chk(i)) ans = i; if(sum / i > ans && chk(sum / i)) ans = sum / i; } } printf("%lld\n", ans); return 0; } -
- 1
信息
- ID
- 11714
- 时间
- 2000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 2
- 上传者