【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; }