【Study Notes】CF1817E Half-sum

First, the optimal greedy strategy is: after sorting the original array , select a dividing point ppp , then for[ 1 , p ] [1,p][1,p ] merge from back to front,[ p + 1 , n ] [p+1,n][p+1,n ] Merge from front to back, and take the difference between the two numbers before and after as the answer. Simulating addition in binary can doO ( n ) O(n)O ( n ) checks. Note that there is no need to maintain high-precision addition evenly (doing so will result in one morelog ⁡ \loglog ) , because we don't care about the intermediate results.

Then, derive it from the perspective of a primary composite function (this form is more concise):

f ( a 1 , . . . , a i , x ) = a x + b f(a_1,...,a_i,x)=ax+b f(a1,...,ai,x)=ax+b,那么 f ( a 1 , . . . , a i , a i + 1 , x ) = a ⋅ a i + 1 + x 2 + b = 1 2 a x + 1 2 a ⋅ a i + 1 + b f(a_1,...,a_i,a_{i+1},x)=a\cdot \frac{a_{i+1}+x}{2}+b=\frac{1}{2}ax+\frac{1}{2}a\cdot a_{i+1}+b f(a1,...,ai,ai+1,x)=a2ai+1+x+b=21ax+21aai+1+b

Note that a = 1 2 ia=\frac{1}{2^{i}}a=2i1, so from the perspective of growth rate, only the top 30 30 should be selected30 items and30 after 3030 items are checked.

Usually, we can eliminate some solutions that are definitely not optimal through neighbor comparison (finding the variation ).

发现 f ( a 1 , . . . , a i + 1 ) − f ( a 1 , . . . , a i ) = 1 2 a ⋅ ( a i + 1 − a i ) = 1 2 i ( a i + 1 − a i ) f(a_1,...,a_{i+1})-f(a_1,...,a_i)=\frac{1}{2}a\cdot(a_{i+1}-a_i)=\frac{1}{2^i}(a_{i+1}-a_i) f(a1,...,ai+1)f(a1,...,ai)=21a(ai+1ai)=2i1(ai+1ai) , so consider the difference array of the original arraydi = ai + 1 − ai d_i=a_{i+1}-a_idi=ai+1ai, then from scheme iii tojjThe change of j is: − di 2 i − ∑ i < k < jdk ( 1 2 k − 1 2 n − k ) + dj 2 n − j -\frac{d_i}{2^i}-\sum_{i <k<j}d_k(\frac{1}{2^k}-\frac{1}{2^{nk}})+\frac{d_j}{2^{nj}}2idii<k<jdk(2k12nk1)+2n jdj

Note that if di = 0 d_i=0di=0nana ii_i will definitely not become the optimal dividing point, so weshould satisfy di > 0 d_i>0di>0 . Then, wheni ≤ j ≤ n 2 i\le j\le \frac{n}{2}ij2nWhen , the middle formula must be ≤ 0 \le 00 , only whenn − j ≤ i + 30 nj\le i+30nji+30 years later may be the answer. That is:j ≥ n − i − 30 j\ge ni-30jni30 . In this way, we only need to find the first one that satisfies≤ n 2 − 30 \le \frac{n}{2}-302n30 anddi > 0 d_i>0di>0 position, this must be optimal; if it does not exist, then test[ n 2 − 30 , n 2 ] [\frac{n}{2}-30,\frac{n}{2}][2n30,2n] in all locations. The equivalent implementation is, before checking30 3030 items satisfydi > 0 d_i>0di>0 position. Forj > n 2 j>\frac{n}{2}j>2nThe situation is obviously the same.

Complexity O ( n log ⁡ V ) O(n\log V)O ( nlogV)

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define fi first
#define se second
#define db double
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
const int mod=1e9+7;
const int N=1e6+65;
int T,n,m,res;
ll a[N],inv2=(mod+1)/2;
ll b[N],c[N],r[N];
void solve(int x){
    
    
    for(int i=0;i<=n+60;i++)b[i]=c[i]=0;
    for(int i=x;i>=1;i--){
    
    
        int j=i-(i==x);
        b[n-j]+=a[i];
    }for(int i=0;i<=n+60;i++)b[i+1]+=b[i]/2,b[i]%=2;
    for(int i=x+1;i<=n;i++){
    
    
        int j=n-i+1-(i==x+1);
        c[n-j]+=a[i];
    }for(int i=0;i<=n+60;i++)c[i+1]+=c[i]/2,c[i]%=2;
    for(int i=0;i<=n+60;i++){
    
    
        c[i]-=b[i];if(c[i]<0)c[i]+=2,c[i+1]--;
    }
    int it=n+60;while(it&&c[it]==r[it])it--;
    if(c[it]>r[it]){
    
    
        for(int i=0;i<=n+60;i++)r[i]=c[i];
        res=x;
    }
}
int main(){
    
    
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    cin>>T;
    while(T--){
    
    
        cin>>n;for(int i=1;i<=n;i++)cin>>a[i];
        sort(a+1,a+1+n);res=1;for(int i=0;i<=n+60;i++)r[i]=0;
        int j=1;
        for(int i=1;i<=30;i++){
    
    
            while(j<n&&a[j]==a[j+1])j++;
            if(j==n)break;solve(j),j++;
        }j=n;
        for(int i=1;i<=30;i++){
    
    
            while(j>1&&a[j]==a[j-1])j--;
            if(j==1)break;solve(j-1),j--;
        }ll x=a[res];
        for(int i=res-1;i>=1;i--)x=(x+a[i])*inv2%mod;
        ll y=a[res+1];
        for(int i=res+2;i<=n;i++)y=(y+a[i])*inv2%mod;
        cout<<(y-x+mod)%mod<<"\n";
    }
}

Guess you like

Origin blog.csdn.net/cqbzlydd/article/details/133276116