• 【倍增】 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();
    }
    
  • 相关阅读:
    Fortran学习记录1(Fortran数据类型)
    ABAQUS学习记录1——用户子程序综述
    Abaqus用户子程序umat的学习
    信号基础知识---线阵
    信号基础知识--FFT DFT
    信号基础知识
    服务器文件打压缩包下载(java)
    网页鼠标特效-点击漂浮文字
    jQuery父子页面之间元素、方法获取、调用
    常用数字与字母的正则表达式
  • 原文地址:https://www.cnblogs.com/hhyx/p/13047364.html
Copyright © 2020-2023  润新知