• 【倍增】 Genius acm


    传送门

    题意

    给定一个长度为(n)的整数序列(a),以及一个数(t),和一个(m),将(a)分成子序列,子序列中满足从中取出(m)对数(不能重复取,如果不够取到不能取为止),使得每一对数的差的平方和最大,
    将这个最大值定义为序列的校验值,使得子序列的校验值小于等于(t),问最少能够分成多少个子序列

    数据范围

    (egin{array}{l}1 leq K leq 12 \ 1 leq N, M leq 500000 \ 0 leq T leq 10^{18} \ 0 leq A_{i} leq 2^{20}end{array})

    题解

    对于一段序列来说,取最大的和最小的组成一对,这样计算出来的和是最大的

    • 初始化(p=1,r = l)

    • 求出([ l , r+p ])的校验值

      • 如果校验值(<=t, r=r + p,p=p imes 2),否则(p= frac{p}{2})
    • 重复上步,直到(p=0)

    • 以上的过程最多进行(O(logn))次,每次循环都对$ r-l$ 排序,总体为O((nlog^{2}n)),每次求校验值的时候不需要快速排序,用类似归并排序的算法只需要对新增部分排序

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define rep(i,a,n) for(int i=a;i<n;i++)
    #define per(i,a,n) for(int i=n-1;i>=a;i--)
    
    const int N=5e5+10;
    int _;
    int n,m;
    ll t;
    int a[N],b[N],c[N];
    int last;
    void merge(int l,int mid,int r){   
        int i = l,j = mid+1;
        for(int k=l;k<=r;k++){
            if(j > r || (i <= mid && b[i] < b[j]))
                c[k] = b[i++];
            else c[k] = b[j++];
        }
    }
    long long cal(int l,int r){
        if(r > n) r = n;
        int cp = min(m,(r-l+1)/2);
        for(int i=last+1,i<=r;i++) b[i] = a[i];
        sort(b+last+1,b+r+1);
        merge(l,last,r);
        ll res=0;
        rep(i,0,cp) 
            res += 1ll * (c[r-i]-c[l+i])*1ll*(c[r-i]-c[l+i]);
        return res;
    }
    
    void solve()
    {
        cin>>n>>m>>t;
        for(int i=1;i<=n;i++) cin>>a[i];
        last=1;
        int ans=0,l=1,r=1;
        b[1]=a[1];
        while(l<=n){
            int p=1;
            while(p){  
                long long res = cal(l,r+p);
                if(res <= t){
                    last = r = min( r+p , n );
                    for(int i=l;i<=r;i++) b[i]=c[i]; // 保存有序形式
                    if(r==n) break;
                    p*=2;
                }
                else p/=2;
            }
            ans++;
            l=r+1;
        }
        cout<<ans<<endl;
    }   
    
    int main(){
        cin>>_;
        while(_--)
            solve();
    }
    
  • 相关阅读:
    Java学习之Math类理解
    Java学习之集合框架的迭代器--Iteratorjk及ListItertor接口
    Java学习关于随机数工具类--Random类
    集合框架学习之List接口
    Java学习关于集合框架的基础接口--Collection接口
    Java基础学习之数组基本属性和方法
    Java学习关于时间操作的应用类--Date类、Calendar类及其子类
    Java学习--异常处理及其应用类
    LR百分比模式
    lr函数之lr_eval_string()函数的使用学习
  • 原文地址:https://www.cnblogs.com/hhyx/p/13047364.html
Copyright © 2020-2023  润新知