zoukankan      html  css  js  c++  java
  • 830C

    分块+二分

    这道题思路很巧妙

    我们大概可以推出一个式子sigma(d-[(ai-1)%d+1])<=k,要求求出d的最大值

    然后我们化简一下,sigma(d-[(ai-1)-[(ai-1)/d]*d+1])<=k -> sigma(d-ai-[(ai-1)/d]*d)<=k

    直接枚举肯定炸,但是我们看见里面有一个下取整除法,我们想到了什么?莫比乌斯反演中的分块技巧!那么我们可以通过分块来减少枚举d的复杂度,然后在一定取值范围内二分就行了!

    然后,我们对于每个ai-1查找分块对应端点的最小值,也就是一段使得(ai-1)/d第一个变化的值,而其他值没有变化,也就是说我们对于每个ai枚举分块端点值后,每两个值相邻区间的值不会改变任何一个(ai-1)/d的值。

    然后每个ai有sqrt(ai)个值,那么一共就有n*sqrt(max(ai))的值,然后我们从大到小枚举每个值,如果一个值满足条件,那么我们需要二分找出满足答案的最大值,因为这个值只是在从这个值到下一个值-1这一段区间内任意(ai-1)/d不变,但是不一定满足,由于现在(ai-1)/d不变,那么上面那个式子就满足单调性了,于是就可以二分了。

    如果枚举的值范围过大,我们在看见除法的情况下可以用分块优化,可以大大降低复杂度,因为分块求出使一个值变化的最小的除数,这样我们就可以求出所有区间使得取这个区间内任意一个值所有数做除法的商不变

    最后push_back(j)是(ai-1)/d==0,其实也就是ai

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 110;
    int n;
    long long k, ans, sum, m;
    long long a[N];
    vector<long long> v;
    int main()
    {
        scanf("%d%I64d", &n, &k);
        for(int i = 1; i <= n; ++i) scanf("%I64d", &a[i]), sum += a[i], m = max(m, a[i]);
        long long tot = k + m;
        for(int i = 1; i <= n ; ++i)
        {
            long long j, t;
            for(j = 1, t = 0; j < a[i] && t < a[i]; j = t + 1)
                v.push_back(j), t = (a[i] - 1) / ((a[i] - 1) / j);
            v.push_back(j);    
        }
        for(int i = 0; i < v.size(); ++i) printf("%I64d ", v[i]);
        puts("");
        sort(v.begin(), v.end());
        v.erase(unique(v.begin(), v.end()), v.end());
        v.push_back(100000000000000ll);
        for(int i = v.size() - 1; i >= 0; --i)
        {
            long long x = v[i];
            long long tot = 0;
            for(int j = 1; j <= n; ++j) tot += (a[j] - 1) / x;
            if(x * tot <= k + sum - (long long)n * x) 
            {
                long long l = x - 1, r = v[i + 1];
                while(r - l > 1ll)
                {
                    long long mid = (l + r) >> 1ll;
                    if(mid * tot <= k + sum - (long long)n * mid) l = ans = mid;
                    else r = mid;
                }    
                break; 
            }
        }        
        cout << ans << endl;
        return 0;
    }
    View Code
  • 相关阅读:
    [TJOI2013]循环格
    [CQOI2017]小Q的表格
    【51nod 1514】 美妙的序列
    【bzoj3456】 城市规划
    [SHOI2010]最小生成树
    CF438E The Child and Binary Tree
    bzoj 4712: 洪水
    POJ-3069 Saruman's Army---区间选点
    POJ-3617 Best Cow Line---字符串贪心
    HDU-1850 Being a Good Boy in Spring Festival---尼姆博奕的运用
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7445417.html
Copyright © 2011-2022 走看看