【GCD枚举因子+环上问题】代码源每日一题div1 最大公约数

最大公约数 - 题目 - Daimayuan Online Judge

题意:

思路:

思路上挺好想的

要让GCD(sum1,sum2,sum3,....sumk)最大,惯用套路,令其为K,那就是让K最大

sum1=k1*K

sum2=k2*K

....

所以很自然想到了枚举sum的因子

然后就是给序列分段,让尽可能多的段的段和gcd为因子x

这个又是典中典的东西,直接求个前缀和%x就好了,看看mp[pre[i]%x]的最大值就是最多能分成几段,然后记录答案即可

还有环的条件,我想的是倍增数组之后O(N)枚举区间,但是这样肯定T

事实上都不需要枚举,因为你一段区间和%x为0了,头尾相接%x也一定是0了

所以根本不需要管环

还有一个很显然的点我没有想到:如果一个序列能分成多段,那么自然可以分成更少段,因此答案数组需要求个后缀最大值

Code:

#include <bits/stdc++.h>

#define low(x) (x&(-x))
#define int long long

using namespace std;

const int mxn=1e5+10;

int N,sum=0;
int a[mxn],pre[mxn],ans[mxn];

void calc(int x){
    int cnt=0;
    map<int,int> mp;
    for(int i=1;i<=N;i++){
        mp[pre[i]%x]++;
        cnt=max(cnt,mp[pre[i]%x]);
    }
    ans[cnt]=max(ans[cnt],x);
}
void solve(){
    cin>>N;
    for(int i=1;i<=N;i++){
        cin>>a[i];
        pre[i]=pre[i-1]+a[i];
    }
    set<int> S;
    for(int i=1;i<=pre[N]/i;i++){
        if(pre[N]%i==0){
            S.insert(i);
            if(i!=pre[N]/i) S.insert(pre[N]/i);
        }
    }
    for(auto it:S) calc(it);
    for(int i=N;i>=1;i--) ans[i]=max(ans[i],ans[i+1]);
    for(int i=1;i<=N;i++) cout<<ans[i]<<'\n';
}
signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int __=1;//cin>>__;
    while(__--)solve();return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值