kacho65535の競プロメモ

Atcoderと戯れる予定のブログです

yukicoder:No.944 煎っぞ!

計算量解析を大分さぼったけど投げたらACできた...(あまりよろしくない)

問題概要


yukicoder.me

N 個の要素からなる数列を、順序を維持したまま k 等分( k 個の連続部分列の要素の和が等しくなるように分ける)するときの k の最大値を求めよ。

制約

1 \leq N \leq 10^{5}

1 \leq A_{i} \leq 10^{2}

解法


まず、 N 個の要素の和 S の最大値が 10^{7} と小さめであることに着目する。

k 等分できるとき、 kS の約数であることを考慮すると、約数の個数は 2×\sqrt{S} 個を超えないため(実際には大分少ない)、 k の候補として S の約数を全て調べても 1 回のチェックが O(N) でできるので制限時間に間に合う。

枝狩りをしたところ 26ms でACできた。

コード


#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define mod 1000000007ll
#define loop(i, n) for (int i = 0; i < n; i++)
#define all(v) v.begin(), v.end()
#define putout(a) cout << a << '\n'
#define Sum(v) accumulate(all(v), 0ll)
template <typename T>
bool chmax(T &a, const T &b)
{
    if (a < b)
    {
        a = b; // aをbで更新
        return true;
    }
    return false;
}
int main()
{
    ll N;
    cin >> N;
    vector<ll> A(N);
    ll maxx = 0;
    loop(i, N)
    {
        cin >> A[i];
        chmax(maxx, A[i]);
    }
    ll S = Sum(A);
    for (int i = N; i >= 1; i--)
    {
        if (S % i != 0 || (S / i) < maxx)
            continue;
        ll now = 0;
        bool ng = false;
        ll div = S / i; //各豆のおいしさ
        loop(j, N)
        {
            now += A[j];
            if (now > div)
            {
                ng = true;
                break;
            }
            if (now == div)
                now = 0;
        }
        if (ng || now != 0)
            continue;
        putout(i);
        return 0;
    }
    return 0;
}