NKOJ P3545 approach (monotone queue/binary lookup)

Keywords: PHP less

Time limit: 10000 MS Space limit: 165536 KB
Problem Description

For a number sequence A, there are several queries. For each query, it is required to find a non-empty continuous segment in sequence A so that the absolute value of the sum of the segments is as close as possible to P.

Input format

The first line has two numbers N and T, which indicate the length of the sequence and the number of queries.
The next line contains N integers, representing the A sequence. Next, in line T, a number P per line indicates a query.

Output format

A total of T lines are output, each line corresponds to an answer to a query.
Output of three numbers: the first number is the closest to P that can be achieved, and the last two numbers L and R indicate that the number of L to R in A sequence can achieve this answer.
If there are multiple solutions, the output L is the smallest solution.
If there are multiple solutions, output the solution with the smallest R.

sample input

Input Sample 1
5 1 
-10 -5 0 5 10 
3  

Sample input 2
6 2 
-2 5 3 0 -3 -4 

6

Sample input 3
7 2 
-2 -1 -2 4 1 -3 7 

6

sample output

Sample output 1
5 2 2

Sample output 2
1 1 6
6 1 3
Sample output 3
0 1 5 
6 2 7

Tips

[Data Scope]
30% of the data is 1<=N<=1,000.
60% of the data is 1<=N<=10,000.
100% data 1 <=N<=100,000, absolute value of numbers in A sequence <=10,000, T<=100, inquiry number <=10^9

 
 
Dichotomy

Satisfies | sum [j] - sum [i-1] | >= P or | sum [j] - sum [i-1] | <= p
I remember my boss saying that absolute values can be turned on.
Open and change shape
Sum [j] + P <= sum [i-1];
Or sum [j]-p<=sum [i-1];
At this point, we can reproduce the sum array to the struct sum2 array as follows
val values are sorted, of course, the replicated id should be preserved, that is, we need to sort the replicated struct structure array
Then copy the va value of the array to the sum3 array
Then enumerate N with j
Next, binary pairs sum[j]-p and sum[j]+p look for the minimum value of >= in the sum3 array
The id is recorded in the structure of sum2 and the subscripts of sum3 and sum2 are the same.
ans=min{abs(abs(sum3 [binary subscript] - sum[j] (- or +) p)}
      
           {
                r=j;
l=sum2 [enumerated subscript]. ID + 1; / if (ans > ABS (abs (sum3 [subscript] - sum[j]) (+/-) p))

          }
if(ans==abs(abs(sum3 [subscript]-sum [j]-/+p))
{
if(l==sum2 [subscript]. ID + 1 & & R > j)
{
l=sum2 [subscript]. id+1;
r=j;
}
If (l > sum2 [subscript]. id+1)
{
l=sum2 [subscript]. id+1;
r=j;
}
}
Then cout
                                
//
#include<bits/stdc++.h>
using namespace std;
#define maxnn 102000
#define ll long long  
ll sum[maxnn];
ll sum3[maxnn];
ll n,t;
struct node
{
    ll id,va;
    
}sum1[maxnn];
bool cmp(node a,node b)
{
    if(a.va==b.va)
    return a.id<b.id;
    else
    return a.va<b.va;
    
}
int main()
{
    cin>>n>>t;
    ll x;
    ll uu;
    ll p;
    ll ans=1000000000000;
    sum1[0].id=0;
    sum1[0].va=0;
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&x);
        sum[i]=sum[i-1]+x;
        sum1[i].va=sum[i];
        sum1[i].id=i;
    }
    sort(sum1,sum1+1+n,cmp);
    for(int i=0;i<=n;i++)
    {
        sum3[i]=sum1[i].va;
    }
    for(int i=1;i<=t;i++)
    {
        ans=100000000000;
        ll l=10000000000,r=10000000000;
        cin>>p;
        for(int j=1;j<=n;j++)
        {
            int xx=lower_bound(sum3,sum3+1+n,sum[j]+p)-sum3;//j
            int xxx=lower_bound(sum3,sum3+1+n,sum[j]-p)-sum3;
            if(ans>abs(abs(sum3[xx]-sum[j])-p))
            {
                uu=abs(sum3[xx]-sum[j]);
                ans=abs(abs(sum3[xx]-sum[j])-p);
                r=j;
                l=sum1[xx].id+1;
            }
            if(ans==abs(abs(sum3[xx]-sum[j])-p))
            {
                if(l==sum1[xx].id+1&&r>j)
                {
                    l=sum1[xx].id+1;
                    r=j;
                }
                if(l>sum1[xx].id+1)
                {
                    l=sum1[xx].id+1;
                    r=j;
                }
            }
            
        if(ans>abs(abs(sum3[xxx]-sum[j])-p))
            {
                uu=abs(sum3[xxx]-sum[j]);
                    ans=abs(abs(sum3[xxx]-sum[j])-p);
                    r=j;
                l=sum1[xxx].id+1;
            }
                if(ans==abs(abs(sum3[xxx]-sum[j])-p))
            {
                if(l==sum1[xxx].id+1&&r>j)
                {
                    l=sum1[xxx].id+1;
                    r=j;
                }
                if(l>sum1[xxx].id+1)
                {
                    l=sum1[xxx].id+1;
                    r=j;
                }
            }
            
        }
         cout<<uu<<" "<<l<<" "<<r<<endl;
         
    }
    
    
}

Monotonic queue

Run every time you ask.
Obviously, the first idea is not feasible. Preprocessing the sum and difference of all interval prefixes is O(N2).
This is the case. Then only consider the second way of thinking. Given the data range, it can only withstand time complexity O(NT) or faster algorithms.
Every time I ask O(N)
So it's easy to think of monotonous queues.
However, there is a problem: prefixes and arrays do not satisfy monotony, what should we do?
Back to the question itself. The problem is equivalent to the following form: find a pair of (i,j)
Make | sum[i] sum[j] | as close as possible to P. Notice the form of absolute value, then (i,j) can be disordered. that is
Say, i,j
The size of the relationship in the search for answers has no effect, then we can force ranking, there is monotony.
You might as well sort prefixes from large to small. For i, J (j > i)
From small to large, when sum[i] sum[j] is greater than or equal to P, a larger J can't get a bigger answer.
Case. When the sum [head] sum [tail] is less than P, the absolute value of the difference satisfied in this queue is closest to one of P.
For prefixes and apparently sum [head] and sum [tail]
This is the case. This obviously satisfies the monotonic queue model.
Satisfy the remaining conditions and pay attention to the details.
 
code:
#include<stdio.h>
#include<algorithm>
#include<deque>
#include<iostream>
#define MAXN 100005
using namespace std;

int N,T,R,L,Ans,P,Delta;

struct node{int id,v;}sum[MAXN];
bool operator<(node x,node y){if(x.v==y.v)return x.id<y.id;return x.v>y.v;}

void Solve()
{
    Delta=L=R=1e9;

    deque<int>Q;
    int i,t,a,b,tmp;

    for(i=0;i<=N;i++)
    {
        while(Q.size()&&sum[Q.front()].v-sum[i].v>=P)
        {
            t=Q.front();
            tmp=sum[t].v-sum[i].v;
            a=min(sum[t].id,sum[i].id);
            b=max(sum[t].id,sum[i].id);

            if(tmp-P<=Delta)
            {
                if(tmp-P==Delta)
                {
                    if(L>=a)
                    {
                        if(L==a)R=min(R,b);
                        else L=a,R=b;
                    }
                }
                else
                {
                    Ans=tmp;
                    L=a;R=b;
                }
                Delta=tmp-P;
            }
            Q.pop_front();
        }
        Q.push_back(i);
        t=Q.front();
        tmp=sum[t].v-sum[i].v;
        a=min(sum[t].id,sum[i].id);
        b=max(sum[t].id,sum[i].id);
        if(P-tmp<=Delta&&Q.size()!=1)
        {
            if(P-tmp==Delta)
            {
                if(L>=a)
                {
                    if(L==a)R=min(R,b);
                    else L=a,R=b;
                }
            }
            else
            {
                Ans=tmp;
                L=a;R=b;
            }
            Delta=P-tmp;
        }
    }

    printf("%d %d %d\n",Ans,L+1,R);
}

int main()
{
    int i,x;

    scanf("%d%d",&N,&T);
    for(i=1;i<=N;i++)
    {
        scanf("%d",&x);
        sum[i].v=sum[i-1].v+x;
        sum[i].id=i;
    }

    sort(sum,sum+N+1);

    for(i=1;i<=T;i++)
    {
        scanf("%d",&P);
        Solve();
    }
}

 

Posted by henka on Fri, 19 Jul 2019 03:13:19 -0700