4366. 上课睡觉
摘要
Title: 4366. 上课睡觉
Tag: 约数
Memory Limit: 64 MB
Time Limit: 1000 ms
Powered by:NEFU AB-IN
4366. 上课睡觉
-
题意
有 N 堆石子,每堆的石子数量分别为 a1,a2,…,aN。
你可以对石子堆进行合并操作,将两个相邻的石子堆合并为一个石子堆,例如,如果 a=[1,2,3,4,5],合并第 2,3 堆石子,则石子堆集合变为 a=[1,5,4,5]。
我们希望通过尽可能少的操作,使得石子堆集合中的每堆石子的数量都相同。
请你输出所需的最少操作次数。
本题一定有解,因为可以将所有石子堆合并为一堆。 -
思路
约数的二级结论:
- int范围内,最多的约数有1600个
- 720720,有240个约数
- 一个数的约数大约是 logn 个
先算出整个数组的总和sum,如果要分段,每一段的总和必须是sum的约数,那么就可以枚举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
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/*
* @Author: NEFU AB-IN
* @Date: 2023-01-01 20:33:22
* @FilePath: \Acwing\4366\4366.cpp
* @LastEditTime: 2023-01-01 20:57:14
*/
using namespace std;
typedef pair<int, int> PII;
// #undef N
// const int N = 1e5 + 10;
void solve()
{
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; ++i)
cin >> a[i];
int sum = accumulate(a.begin(), a.end(), 0);
vector<int> b;
for (int i = 1; i * i <= sum; ++i)
{
if (sum % i == 0)
{
b.push_back(i);
if (i * i != sum)
b.push_back(sum / i);
}
}
if (!SZ(b))
{
cout << "0\n";
return;
}
sort(b.begin(), b.end());
auto fun = [&](int x) {
int cnt = 0, tmp = 0, flag = 0;
for (int i = 0; i < n; ++i)
{
if (flag)
cnt++;
tmp += a[i];
flag = 1;
if (tmp == x)
tmp = 0, flag = 0;
if (tmp > x)
return INT_MAX;
}
return cnt;
};
int ans = INT_MAX;
for (auto x : b)
{
ans = min(ans, fun(x));
}
cout << ans << '\n';
return;
}
signed main()
{
IOS;
int T;
cin >> T;
while (T--)
solve();
return 0;
}