zoukankan      html  css  js  c++  java
  • 【JZOJ4922】【NOIP2017提高组模拟12.17】环

    题目描述

    小A有一个环,环上有n个正整数。他有特殊的能力,能将环切成k段,每段包含一个或者多个数字。对于一个切分方案,小A将以如下方式计算优美程度:
    首先对于每一段,求出他们的数字和。然后对于每段的和,求出他们的最大公约数,即为优美程度。
    他想通过合理地使用他的特殊能力,使得切分方案的优美程度最大。

    数据范围

    对于100%的数据,n<=2000,1<=ai<=50000000(5e7)

    =w=

    sum=ai
    那么答案一定是sum的约数。
    证明:
    如果存在一个答案ans不是sum的约数,那么切分出来的每一段之和都会是ans的倍数;
    每一段的和(也就是sum)就会是ans的倍数。
    矛盾。

    如果切分i段的答案为ans[i],那么对于所有j>i,切分j段的答案至少为ans[i]
    证明:
    通过子段合并,显然可得。


    于是我们得出思路:
    枚举sum的一个约数i,容易用哈希表加上O(2n)的时间得出最小的j使得ans[j]=i

    代码

    // DO NOT FORGET TO OPEN LL
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const char* fin="aP1.in";
    const char* fout="aP1.out";
    const ll inf=0x7fffffff;
    const ll maxn=4007,maxp=100000,maxh=99997;
    ll n,m,i,j,k;
    ll a[maxn],w[maxn],ans[maxn],pre[maxn],sum[maxn];
    ll id[maxn];
    ll h[maxh],cnt[maxh];
    ll getsum(ll l,ll r){
        return pre[r]-pre[l-1];
    }
    ll hash(ll v){
        ll k=v%maxh;
        while (h[k] && h[k]!=v) k=(k+1)%maxh;
        return k;
    }
    void add(ll x){
        ll i=hash(sum[x]+1);
        id[x]=i;
        if (h[i]==0){
            h[i]=sum[x]+1;
            cnt[i]=1;
        }else cnt[i]++;
    }
    void del(ll x){
        ll i=id[x];
        cnt[i]--;
        if (!cnt[i]) h[i]=0;
    }
    ll find(ll x){
        ll i=id[x];
        if (h[i]) return cnt[i];
        else return 0;
    }
    void solve(ll v){
        ll i,j,k,cnt=0,tmp=0;
        sum[0]=0;
        for (i=1;i<=n;i++) sum[i]=(sum[i-1]+a[i])%v;
        for (i=1;i<=n/2;i++) add(i);
        for (i=n/2+1;i<=n;i++){
            //tong[sum[i-n/2]]--;
            del(i-n/2);
            add(i);
            if (sum[i]==sum[i-n/2]){
                tmp=max(find(i-n/2),tmp);
            }
        }
        w[tmp]=max(w[tmp],v);
        for (i=n/2+1;i<=n;i++) del(i);
    }
    int main(){
        scanf("%lld",&n);
        for (i=1;i<=n;i++) scanf("%lld",&a[i]),m+=a[i];
        for (i=n+1,j=n*2;i<=j;i++) a[i]=a[i-n];
        for (i=1;i<=n;i++) pre[i]=a[i]+pre[i-1];
        n=n*2;
        for (i=1,j=(ll)sqrt(m);i<=j;i++){
            if (m%i==0) solve(i),solve(m/i);
        }
        k=1;
        for (i=n/2;i>0;i--){
            k=max(k,w[i]);
            ans[i]=k;
        }
        for (i=1;i<=n/2;i++) printf("%lld
    ",ans[i]);
        return 0;
    }

    =o=

    其实优化容易想到。
    我没深入思考= =

  • 相关阅读:
    准确率,召回率,F值
    残差
    字典学习
    深度学习
    cnn 滤波
    tensorflow
    kaggle 泰坦尼克
    python matplotlib
    数学家西蒙斯:华尔街最赚钱的基金经理
    Oracle学习笔记:删除数据空格(trim、ltrim、rtrim函数)
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6714814.html
Copyright © 2011-2022 走看看