상세 컨텐츠

본문 제목

오름차순 (JUNGOL 7020)

PS,CP

by 코딩생활 2026. 5. 22. 09:00

본문

https://jungol.co.kr/problem/7020


아이디어

diffi를 다음과 같이 정의합시다.

diffi=aix>=ai-1인 가장 작은 정수 x

 

그리고 resi=ai에 2를 곱하는 횟수 라고 정의합시다. 그러면 resi=max(0,resi-1+diffi)라고 할 수 있습니다. 이떄 구간에 관계없이 diff값은 고정되어있으므로 어떠한 인덱스 i의 res값이 0이라면, i보다 크고 res값이 0이되는 최소의 j를 전처리할 수 있습니다. 물론 그러면 희소 배열을 이용해서 i보다 큰 인덱스중에서 res값이 0이되는 2k번째로 작은 j를 찾을 수 있습니다.

 

그리고 구간 res값에 0이 없는 구간 [i,j]가 주어지면 solve(i,j)=(diffj+2*diffj-1+3*diffj-2+...+(j-i+1)*diffi값)을 O(1)에 구할 수 있습니다. 이를 확장시키면 res값이 0인 인덱스 i와 그 다음으로 res값이 0인 인덱스 j에 대하여 [i+1,j-1]의 값들을 모두 갱신시키는 최소 횟수는 solve(i+1,j-1)이 됩니다. 이 값 또한 희소 배열에 넣어주면 하나의 쿼리에 대해 O(log N)에 해결해줄 수 있습니다.


아이디어

#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#define ll long long
using namespace std;

ll GetDiff(ll before,ll now)
{
    if (before<now)
    {
        ll cnt=0;
        while (before*2<=now)
        {
            cnt++;
            before*=2;
        }
        return -cnt;
    }
    else
    {
        ll cnt=0;
        while (now<before)
        {
            cnt++;
            now*=2;
        }
        return cnt;
    }
}

ll N;
ll Diff[252525]={0};
ll Next[252525][22]={0},val[252525][22]={0}; //Next[i][0]: Diff[i+1]+...+Diff[j]<=0인 최소의 j, 없으면 N+1
ll Suffix[252525]={0},MulSuffix[252525]={0};

ll solve(ll i,ll j)
{
    return (MulSuffix[i]-MulSuffix[j+1]-(N-j)*(Suffix[i]-Suffix[j+1]));
}

int main()
{
    ios_base::sync_with_stdio(false); cin.tie(NULL);
    ll Q,i,a,b,before,now;

    cin>>N>>Q>>before;
    for (i=2;i<=N;i++)
    {
        cin>>now;
        Diff[i]=GetDiff(before,now);
        before=now;
    }

    ll sum=0;
    stack <pair <ll,ll> > stk;
    for (i=N;i>=1;i--)
    {
        while (stk.size() && stk.top().first<sum) stk.pop();
        if (stk.size()) Next[i][0]=stk.top().second;
        else Next[i][0]=N+1;

        for (ll j=1;j<=20;j++)
            Next[i][j]=Next[Next[i][j-1]][j-1];

        stk.push({sum,i});
        sum+=Diff[i];
    }
    for (i=N;i>=1;i--)
    {
        Suffix[i]=Suffix[i+1]+Diff[i];
        MulSuffix[i]=MulSuffix[i+1]+Diff[i]*(N-i+1);
    }
    /*
    cout<<"Diff: ";
    for (i=1;i<=N;i++)
    {
        cout<<Diff[i]<<' ';
    }
    cout<<"\nSuffix: ";
    for (i=1;i<=N;i++)
    {
        cout<<Suffix[i]<<' ';
    }
    cout<<"\nMulSuffix: ";
    for (i=1;i<=N;i++)
    {
        cout<<MulSuffix[i]<<' ';
    }
    cout<<"\nNext: ";
    for (i=1;i<=N;i++)
    {
        cout<<Next[i][0]<<' ';
    }
    cout<<"\n";

    for (i=1;i<=N;i++)
    {
        cout<<solve(i+1,Next[i][0]-1)<<' ';
    }
    cout<<"\n";
    */

    for (i=N;i>=1;i--)
    {
        val[i][0]=solve(i+1,Next[i][0]-1);
        for (ll j=1;j<=20;j++)
        {
            Next[i][j]=Next[Next[i][j-1]][j-1];
            val[i][j]=val[i][j-1]+val[Next[i][j-1]][j-1];
        }
    }
    
    for (i=0;i<Q;i++)
    {
        cin>>a>>b;

        ll res=0;
        for (ll j=20;j>=0;j--)
        {
            if (Next[a][j]!=0 && Next[a][j]<=b)
            {
                res+=val[a][j];
                a=Next[a][j];
            }
        }

        //cout<<a<<" -> "<<b<<"\n";
        res+=solve(a+1,b);

        cout<<res<<"\n";
    }
}

'PS,CP' 카테고리의 다른 글

매점 (JUNGOL 1117)  (0) 2026.05.23
조약돌 (JUNGOL 5122)  (0) 2026.05.22
광덕산 등산 (JUNGOL 8671)  (0) 2026.05.21
심한 가뭄 (Drought) (JUNGOL 5338)  (0) 2026.05.21
Remilia Plays Soku (CF R 1098 Div.2 - B)  (0) 2026.05.20

관련글 더보기