zoukankan      html  css  js  c++  java
  • [7.18NOIP模拟测试5]砍树 题解(数论分块)

    题面(加密)

    又考没学的姿势……不带这么玩的……

    考场上打了个模拟 骗到30分滚粗了

    稍加思考(滑稽)可将题面转化为:

    求一个最大的$d$,使得

      $sum limits _{i=1}^n {(left lceil frac{a_i}{d} ight ceil *d-a_i)} leq k$

    移项可得

      $sum limits _{i=1}^n {left lceil frac{a_i}{d} ight ceil *d} leq k+sum limits _{i=1}^{n}{a_i}$

    那么$leq$ 右侧就变成了一个常量,我们将其设为$C$。

    把$d$除过去,得到

    $sum_limits{i=1}^{n}lceilfrac{a_i}{d} ceil leq lfloorfrac{C}{d} floor$

    此时不等号左右都含有取整,都可以看作分段函数

    我们现在想要最大的d,所以取每段的右端点一定比其它位置更优

    之后求出等号左侧的$lceilfrac{a_i}{d} ceil$就可以通过判断更新答案

    辣么怎么确定右端点呢?

    这时候就需要一个东西:数论分块 (戳这里%大佬blog)

    那么利用数论分块的结论:

    对于形如$sum_{i=1}^{n}{lfloor frac{n}{i} floor}$的式子,

    如果一段的左端点为$l$,那么右端点为$lfloor frac{n}{lfloor frac{n}{l} floor} floor$

    本题得以在$O(n sqrt{a_i})$的优秀复杂度内解决。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=105;
    int n;
    ll lim,a[N],sum,ans;
    int main()
    {
        scanf("%d%lld",&n,&lim);
        sum=lim;
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]),sum+=a[i];
        ll d=0;
        while(sum/(d+1)>0)
        {
            d=sum/(sum/(d+1));
            ll res=0;
            for(int i=1;i<=n;i++)
            {
                ll tmp=a[i]/d;
                if(a[i]%d)tmp+=1;
                res+=tmp*d;
            }
            if(res<=sum)ans=d;
        }
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    rand()和srand()
    advanced regression to predict housing prices
    数学建模
    python的对数
    八月总结——人工智能初学者
    看到的不错的项目
    学习笔记(七): Logistic Regression
    学习笔记(六): Regularization for Simplicity
    An Intuitive Explanation of Convolutional Neural Networks
    CentOS7的mysql5.7-rpm.bundle方式安装
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11208099.html
Copyright © 2011-2022 走看看