zoukankan      html  css  js  c++  java
  • POI 2012 STU-Well

    POI 2012 STU-Well

    洛谷传送门

    题意翻译

    给定一个非负整数序列A,每次操作可以选择一个数然后减掉1,要求进行不超过m次操作使得存在一个A_k=0A**k=0且max(|x_i-x_{i-1}|)max(∣x**ix**i−1∣)最小,输出这个最小值以及此时最小的k


    题解:

    首先看到最大值最小就考虑二分答案。

    直接二分的就是最大斜率最小值。我们进行扫描,如果碰到比当前二分到的答案大的就把它变小,然后递减操作次数。因为是绝对值,所以要正反扫两遍。

    之后我们考虑如何挑一个k使之得0。

    我们发现,对于我们目前二分到的答案,如果有一个位置((k,0)),那么其可行区间一定是过这个点,斜率为二分到的答案的下面的部分。如果有点在上面,肯定是不符合题意的,要减下来。我们又发现,这样的点一定是连续的分布在当前枚举到的K的两侧。所以可以用一个类似于滑动窗口的东西来维护这里。碰到第一个符合题意的就跳出。

    代码:

    #include<cstdio>
    #include<algorithm>
    #define int long long
    using namespace std;
    const int maxn=1e6+6;
    int n,m,ans;
    int a[maxn],b[maxn],sum[maxn];
    int check(int x)
    {
        int tot=0;
        for(int i=1;i<=n;i++)
            b[i]=a[i];
        b[n+1]=-1;
        for(int i=2;i<=n;i++)
            if(b[i]-b[i-1]>x)
            {
                tot+=(b[i]-b[i-1]-x);
                b[i]=b[i-1]+x;
            }
        if(tot>m)
            return 0;
        for(int i=n-1;i>=1;i--)
            if(b[i]-b[i+1]>x)
            {
                tot+=(b[i]-b[i+1]-x);
                b[i]=b[i+1]+x;
            }
        if(tot>m)
            return 0;
        for(int i=1;i<=n;i++)
            sum[i]=sum[i-1]+b[i];
        int l=1,r=1;
        for(int i=1;i<=n;i++)
        {
            int tmp=b[i];
            b[i]=0;
            while(b[l]<x*(i-l))
                l++;
            while(b[r+1]>=x*(r-i+1))
                r++;
            b[i]=tmp;
            int all=(1ll*x*((1ll*(i-l)*(i-l+1)+1ll*(r-i)*(r-i+1))/2));
            if(m-tot>=(sum[r]-sum[l-1])-all)
                return i;
        }
        return 0;
    }
    signed main()
    {
        scanf("%lld%lld",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        if(check(0))
        {
            printf("%lld %lld
    ",check(0),0);
            return 0;
        }
        int l=0,r=1e9;
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(check(mid))
                r=mid;
            else
                l=mid+1;
        }
        printf("%lld %lld
    ",check(r),r);
        return 0;
    }
    
  • 相关阅读:
    python操作 pdf 资料
    PyQt 实现 GUI
    https://zhuanlan.zhihu.com/p/60647332
    [转]框架《Python深度学习基于PyTorch》PDF+代码检测
    python学习资料
    Python虚拟环境打包
    A* 算法详解
    opencv python 图像二值化/简单阈值化/大津阈值法
    语音识别——基于深度学习的中文语音识别tutorial(代码实践)
    OpenCV资料
  • 原文地址:https://www.cnblogs.com/fusiwei/p/14038406.html
Copyright © 2011-2022 走看看