avatar

目录
Codeforces Round #601 (Div. 1) B2. Send Boxes to Alice (Hard Version)

题目相关

题目链接(镜像):Codeforces Round #601 (Div. 1) B2. Send Boxes to Alice (Hard Version)

题目描述:

  英文原文我就不打了这里只放个翻译。。。
  给定 $n$ 个盒子,第 $i$ 个盒子里有 $a_i$ 块巧克力。一个盒子里可能没有巧克力,但保证肯定存在有巧克力的盒子。
  我们希望通过把第 $i$ 个盒子中的巧克力放到第 $i-1$ 或 $i+1$ 个盒子里的操作,实现存在一个 $k(k>1)$ ,使得每个盒子里巧克力个数都是 $k$ 的倍数(当然 $0$ 也是可以的)。
  每移动一块巧克力称为一次操作,求最小的操作数。如果无法实现目标就输出 $-1$ 。

输入输出格式:

输入格式:
  第一行一个整数 $n$ ,代表盒子数。
  第二行 $n$ 个整数,代表每个盒子里巧克力数 $a_i$ 。保证至少有一个 $a_i>0$ 。
输出格式:
  如果无解输出 $-1$ 。否则输出最小操作数。

输入输出样例:

测试点 输入 输出
#1 3
4 8 5
9
#2 5
3 10 2 1 5
2
#4 4
0 5 15 10
0
#1 1
1
-1

样例解释:

  第一个样例:把所有巧克力移到第 $2$ 个盒子中,能被 $17$ 整除。
  第二个样例: $2$ 到 $3$ 一块, $4$ 到 $5$ 一块,能被 $3$ 整除。
  第三个样例:都是 $5$ 的倍数。
  第四个样例:无解。

说明:

  $1≤n≤{10}^6$ ,$1≤a_i≤{10}^6$ 。

博主乱搞

蒟蒻解析:

  先说无解情况:因为巧克力可以随便移,所以只要有两个及其以上巧克力就肯定有解。因为巧克力不能为 $0$ 个,所以当巧克力和为 $1$ 时便无解。
  有解:根据题目,我们知道 $k$ 一定是所有数求和的因数。考虑到最大和为 ${10}^{12}$ ,但我们只需要考虑他的素数因子即可。素数因子不多,我们取其中最小值即可。
  按照这种题的套路,最左边的没有前一个的干扰,我们考虑从左到右处理。有一个尴尬的问题是:最优情况是什么?如果我们对第 $i$ 个盒子进行了操作(假设只对右侧更改),也会对之后的情况造成影响,不好找出最优解。
  我们换一种思路屏蔽掉对后面的影响:设 $s_n=\sum\limits_{i=1}^{n}{a_i}$ (也就是前缀和),问题求解转化为使得每个前缀和为某个 $k$ 的倍数。这样处理之后,我们把第 $i$ 中巧克力分到 $i+1$ 或者反过来从 $i+1$ 拿给 $i$ ,也不会对 $s_{i+1}$ 造成任何影响。每个元素的问题独立了:我们就可以贪心处理,将每个元素处理为离某个 $k$ 最近的数,求和修改值即可。
  考虑是否存在非法情况:调整的时候把其中某个 $a_i$ 搞成负数了?表达在这里就是 $s_i>s_{i+1}$ ?我们可以这样考虑:对第 $i$ 个元素处理,其修改的值最大为 $\frac{k-1}{2}$ (假设 $k$ 是奇数,若是偶数(其实就是 $2$ 了)则把第 $i$ 个的巧克力分给 $i+1$ 保证后面没有负数)。若情况违法,则说明第 $i+1$ 个元素处理后 $a_{i+1}<0$ ,也即 $a_{i+1}<\frac{k-1}{2}$ ,更确切地说: $a_{i+1}≤\frac{k-1}{2}-1$ 。初始最小是 $0$ ,所以最极端情况就是处理后 $a_i=-\frac{k-1}{2}+1>\frac{k-1}{2}$ ,在后续处理中这个数肯定是要被加回 $0$ 的,所以没有影响(相当于后面先补过来了)。
  也许还有一种情况是无限继承下去一直是负数?其实情况不存在。我们已经知道任意出现负数的情况肯定处理后被添为 $0$ 。是否都能成功变成 $0$ ?我们已经确保总和是 $k$ 的倍数且不为 $0$ ,最后更改结果一定合法。

蒟蒻代码:

cpp
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
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define ll long long
#define il inline
il int read(){
int x=0,f=1; char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1; ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+ch-'0'; ch=getchar();
}
return x*f;
}
const int maxn=1000010;
int n;
int a[maxn];
ll sum[maxn];
ll ans=9223372036854775807,now,p=2;
ll calc(ll md){
ll tot=0;
for (int i=1;i<=n;++i){
tot+=min(sum[i]%md,md-sum[i]%md);
}
return tot;
}
int main(){
n=read();
for (int i=1;i<=n;++i) a[i]=read();
for (int i=1;i<=n;++i) sum[i]=sum[i-1]+a[i];
if (sum[n]==1){
printf("-1");
return 0;
}
now=sum[n];
while (p*p<=now){
if (!(now%p)){
ans=min(ans,calc(p));
while (!(now%p)) now/=p;
}
++p;
}
if (now>1) ans=min(ans,calc(now));
printf("%I64d",ans);
return 0;
}
文章作者: lonlyn
文章链接: https://lonlyn.gitee.io/blog/2019/12/08/cf1254b/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 lonlyn's blog

评论