T1:农场

题意:有一个长为 $n$ 的序列 $a$,要求将其分成尽可能多的部分,使得每一部分的 $a_i$ 的和相等。求最多能分成的部分数。

$30\%:1\le n\le 1000$

$80\%:1\le n\le 10^5$

$100\%:1\le a_i\le 10,1\le \sum a_i\le 10^6$

这题不难,说一下我在考场的思路:

首先答案应该是 $\sum a_i$ 的约数。那么可以转化一下,变成找到满足要求的最小的和(也是其约数)

进一步想到前缀和。我们发现 $x$ 满足条件,当且仅当 $x,2x,3x\dots$ 全部在前缀和中出现。

于是考场上写了个80分的暴力 $O(n\sqrt{n})$(枚举约数 $O(\sqrt{n})$,判断 $O(n)$)

后来发现可以做到更快:因为总和不超过 $10^6$,因此可以开桶。复杂度 $O(\sigma(n))<O(n\log n)$。

但是 $O(n\sqrt{n})$ 可以过?

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,sum;
 4 int fac[1010],fl;
 5 bool vis[1000100];
 6 void split(int x){    //求出总和的所有约数
 7     for(int i=1;i*i<=x;i++)
 8         if(x%i==0){
 9             fac[++fl]=i;
10             if(i*i!=x) fac[++fl]=x/i;
11         }
12     sort(fac+1,fac+fl+1);
13 }
14 int main(){
15     scanf("%d",&n);
16     for(int i=1;i<=n;i++){
17         int a;
18         scanf("%d",&a);
19         sum+=a;
20         vis[sum]=true;    //对前缀和开桶
21     }
22     split(sum);
23     for(int i=1;i<=fl;i++){
24         bool flag=true;
25         for(int j=fac[i];j<=sum;j+=fac[i])    //判断是否满足
26             if(!vis[j]){    //不满足
27                 flag=false;break;
28             }
29         if(flag){
30             printf("%d\n",sum/fac[i]);return 0;    //答案为总和/单个和=段数
31         }
32     }
33 }
View Code

相关文章:

  • 2021-10-12
  • 2021-08-05
  • 2022-03-04
  • 2022-12-23
  • 2021-06-07
  • 2022-12-23
  • 2021-05-18
  • 2022-12-23
猜你喜欢
  • 2021-06-13
  • 2022-12-23
  • 2021-10-22
  • 2021-09-27
  • 2021-09-05
  • 2021-12-04
  • 2021-07-09
相关资源
相似解决方案