【GDOI2018】D1T1 农场分割(farm) - 倍增/前缀和

题目大意

  n个数,求最多分成几组,使每组的和一样。

Solution of mine

  简单可见n个数的总和一定能被组数整除。

  首先预处理第$i$位向后$2^j$个数的和。

  对于总和$sum$的每个因子x,我们执行$sum/x$次倍增查找下一个位置是否分割点。

  复杂度O(因子个数和)

  因为因子个数和上界是$O(n log n)$,而且卡不满,所以$10^6$就卡过去了。

Solution of std

  延续上面的思想。

  我们发现可以用前缀和的思想来判断某个位置是否是分割点。

  用一个bool数组$f$储存前缀和i是否出现。

  如果

   $\sum_{i=1}^{\frac{sum}{i}}[f[i]]=\frac{sum}{i}$

  则代表该ans可行。

AC Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#define MAXBUF 50000000
using namespace std;
char buffer[MAXBUF];
int pos;
inline void load(){
    fread(buffer,1,MAXBUF,stdin);
    pos=0;
}
inline char gchar(){
    return buffer[pos++];
}
inline int rd(){
    int ret=0;char c=gchar();
    for(;!isdigit(c);)c=gchar();
    for(;isdigit(c);)ret=ret*10+c-'0',c=gchar();
    return ret;
}
int n,x,ans,sum;
bool f[1000010];
inline bool check(int ans){
    for(int j=1;j<=(sum/ans);j++)
        if(!f[ans*j])
            return 0;
    return 1;
}
int main(){
    freopen("farm.in","r",stdin);
    freopen("farm.out","w",stdout);
    load();
    n=rd();
    for(int i=1;i<=n;i++){
        x=rd();
        sum+=x;
        f[sum]=1;
    }
    for(int i=1;i<=sum;i++)
        if(sum%i==0)
            if(check(i)){
                ans=i;
                break;
            }
    printf("%d\n",sum/ans);
    return 0;
}

 

  

 

posted @ 2018-04-30 17:26  skylynf  阅读(513)  评论(0编辑  收藏  举报