제출 #882000

#제출 시각아이디문제언어결과실행 시간메모리
882000alexdd등산 경로 (IZhO12_route)C++17
100 / 100
514 ms43888 KiB
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 1e18;
mt19937 rnd(1823764);
int n,k;
int a[1000005];
int inita[1000005];
int root[1000005];
int tole[1000005];
int tori[1000005];
int lun(int x)
{
    if(tole[x]<=tori[x])
        return tori[x]-tole[x]+1;
    else
        return (n-tole[x]+1) + tori[x];
}
priority_queue<pair<int,int>> pq;
void afis()
{
    /*for(int i=1;i<=n;i++)
        cout<<a[root[i]]<<" ";
    cout<<"\n";*/
    /*for(int i=1;i<=n;i++)
    {
        if(i==1 || root[i]!=root[i-1])
        {
            cout<<root[i]<<"  "<<tole[root[i]]<<" "<<tori[root[i]]<<"  "<<a[root[i]]<<"\n";
        }
    }*/
}
void initializeaza_secvente()
{
    if(a[1]==a[n])
    {
        for(int i=1;i<=n;i++)
        {
            if(a[i]!=a[1])
                break;
            root[i]=1;
            tori[1]=i;
        }
        for(int i=n;i>0;i--)
        {
            if(a[i]!=a[n])
                break;
            root[i]=1;
            tole[1]=i;
        }
        int aux = tori[1]+1;
        root[aux] = aux;
        tole[aux] = aux;
        for(int i=tori[1]+2;i<tole[1];i++)
        {
            if(a[i]!=a[i-1])
            {
                tori[aux]=i-1;
                aux=i;
                tole[i]=i;
            }
            root[i]=aux;
        }
        tori[aux]=tole[1]-1;
    }
    else
    {
        int aux=1;
        root[1]=1;
        tole[1]=1;
        for(int i=2;i<=n;i++)
        {
            if(a[i]!=a[i-1])
            {
                tori[aux]=i-1;
                aux=i;
                tole[i]=i;
            }
            root[i]=aux;
        }
        tori[aux]=n;
    }
    for(int i=1;i<=n;i++)
    {
        if(root[i]==i)
        {
            int tol = tole[i]-1;
            if(tol==0)
                tol=n;
            int tor = tori[i]+1;
            if(tor==n+1)
                tor=1;
            if(a[tol]>a[i] && a[tor]>a[i])
            {
                pq.push({-lun(i),i});
            }
        }
    }
    //for(int i=1;i<=n;i++)
      //  cout<<root[i]<<" ";
}
void unite(int x, int y)
{
    if(lun(x) <= lun(y))
    {
        tole[y] = tole[x];
        int j = tole[x];
        while(j!=tori[x])
        {
            root[j] = y;
            j++;
            if(j==n+1)
                j=0;
        }
        root[tori[x]] = y;
    }
    else
    {
        tori[x] = tori[y];
        int j = tole[y];
        while(j!=tori[y])
        {
            root[j] = x;
            j++;
            if(j==n+1)
                j=0;
        }
        root[tori[y]] = x;
    }
}
void verif_debug()
{

}
int dp[105][1005][1005];///dp[i][cnt][ult]
int solve_dp()
{
    int mnm=INF;
    for(int primu=0;primu<=k;primu++)
    {
        for(int i=0;i<=k;i++)
            for(int j=0;j<=k;j++)
                dp[1][i][j]=INF;
        dp[1][primu][primu] = 0;
        for(int i=2;i<=n;i++)
        {
            for(int cnt=0;cnt<=k;cnt++)
            {
                for(int u=0;u<=cnt;u++)
                {
                    dp[i][cnt][u] = INF;
                    for(int p=0;p+u<=cnt;p++)
                    {
                        dp[i][cnt][u] = min(dp[i][cnt][u], dp[i-1][cnt-u][p] + abs((a[i]+u) - (a[i-1]+p)));
                    }
                    //if(dp[i][cnt][u]<INF) cout<<i<<" "<<cnt<<" "<<u<<"   "<<dp[i][cnt][u]<<"\n";
                }
            }
        }
        for(int cnt=0;cnt<=k;cnt++)
        {
            for(int u=0;u<=cnt;u++)
            {
                mnm = min(mnm, dp[n][cnt][u] + abs((a[n]+u) - (a[1]+primu)));
            }
        }
    }
    mnm = -mnm;
    for(int i=1;i<n;i++)
        mnm += abs(a[i]-a[i+1]);
    mnm += abs(a[1]-a[n]);
    return mnm;
}
int solve_greedy()
{
    bool bl=1;
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]!=a[1])
            bl=0;
        if(i>1) sum += abs(a[i]-a[i-1]);
    }
    sum += abs(a[1]-a[n]);
    if(bl)
    {
        return 0;
        //cout<<0;
        //return 0;
    }
    initializeaza_secvente();

    while(!pq.empty())
    {
        verif_debug();
        int x = pq.top().second;
        pq.pop();
        //cout<<x<<" zzz\n";
        if(lun(x) > k)
            break;
        int tol = tole[x]-1;
        if(tol==0)
            tol=n;
        int tor = tori[x]+1;
        if(tor==n+1)
            tor=1;

        if(lun(x) * (min(a[root[tol]],a[root[tor]]) - a[x]) < k)
        {
            if(a[root[tol]]<a[root[tor]])
            {
                k -= lun(x) * (a[root[tol]] - a[x]);
                a[x] = a[root[tol]];
                unite(root[tol], x);
            }
            else if(a[root[tol]]>a[root[tor]])
            {
                k -= lun(x) * (a[root[tor]] - a[x]);
                a[x] = a[root[tor]];
                unite(x, root[tor]);
            }
            else
            {
                k -= lun(x) * (a[root[tor]] - a[x]);
                a[x] = a[root[tor]];
                unite(root[tol], x);
                unite(root[x], root[tor]);
            }
        }
        else
        {
            a[x] += k / lun(x);
            afis();
            break;
        }
        afis();
        bool eq=1;
        for(int i=1;i<=n;i++)
        {
            if(root[i]!=root[1])
            {
                eq=0;
                break;
            }
        }
        if(eq)
        {
            break;
        }
        ///trebuie sa verificam daca tot sirul ii egal, atunci dam break
        x = root[x];
        tol = tole[x]-1;
        if(tol==0)
            tol=n;
        tor = tori[x]+1;
        if(tor==n+1)
            tor=1;
        if(a[tol] > a[x] && a[tor] > a[x])
        {
            pq.push({-lun(x),x});
        }
    }
    for(int i=1;i<n;i++)
    {
        sum -= abs(a[root[i+1]] - a[root[i]]);
    }
    sum -= abs(a[root[n]] - a[root[1]]);
    return sum;
}
signed main()
{
    int initk;
    cin>>n>>initk;
    k=initk;
    for(int i=1;i<=n;i++)cin>>a[i];
    //cout<<solve_dp();
    cout<<solve_greedy();
    return 0;
    while(1)
    {
        for(int i=1;i<=n;i++)
        {
            inita[i] = rnd()%10;
            a[i] = inita[i];
        }
        k = initk;
        int rezdpp = solve_dp();
        int rezgreedy = solve_greedy();
        //cout<<sum;
        if(rezgreedy!=rezdpp)
        {
            //cout<<rezdpp<<" "<<rezgreedy<<"\n";
            ///do something
            for(int i=1;i<=n;i++)
            {
                cout<<inita[i]<<" ";
            }
            return 0;
        }
    }
    return 0;
}
/**
9 1000
1 1 1 2 2 3 3 1 1

9 1000
1 1 1 3 3 3 3 1 1

10 1000
5 4 3 2 1 1 2 3 4 5

8 3
7 9 1 1 9 9 9 9

n = 2 ?????

3 3
4 8 3

*/
#Verdict Execution timeMemoryGrader output
Fetching results...