1. 程式人生 > >C. Playing Piano

C. Playing Piano

題解:

對於原來的序列把它對應換成新的序列。

新序列保證:同增 同減 相同元素處兩元素不同。(原序列相同)

對於新序列:遞迴出來選擇。dp[i][j]=max(dp[i][k∈D]+1)D表示使得符合規則的數。

dp[i][j]表示在i位置上放j成功走過的步數。(就是滿足條件走了多少步)

dp[i][j]=max(dp[i][k]+1),k是前一個滿足和j條件的。

如果最後dp[n][i]=n存在說明有能夠走到最後的。輸出的時候怎麼判斷是走的哪些步呢。

從dp[n][i]==n的這個i往後遞推,求dp[n-1][k]==n-1的k且k和i滿足對應的關係。從而求出一個可行解。

#include<bits/stdc++.h>
using namespace std;

#define rep(a,b) for(int i=a;i<=b;i++)
#define red(a,b) for(int i=a;i>=b;i--)
#define ULL unsigned long long 
#define LL long long 

const int MOD = 1e9+7;

int dp[200000][100]={0};
int a[200000];
vector<int>v;

int main()
{
    int MAX=5,MIN=1;
    int n;cin>>n;
    rep(1,n)cin>>a[i];
    for(int i=MIN;i<=MAX;i++)
    dp[1][i]=1;

    if(n==1)cout<<"1"<<endl;
    else
    {
        for(int i=2;i<=n;i++)
        {
            for(int j=MIN;j<=MAX;j++)
            {
                if(a[i-1]<a[i])
                {
                    for(int k=j-1;k>=MIN;k--)
                    dp[i][j]=max(dp[i][j],dp[i-1][k]+1);
                }
                else if(a[i-1]>a[i])
                {
                    for(int k=j+1;k<=MAX;k++)
                    dp[i][j]=max(dp[i][j],dp[i-1][k]+1);
                }
                else
                {
                    for(int k=MAX;k>=MIN;k--)
                    {
                    //    cout<<dp[i-1][k]+1<<endl;
                    if(k!=j&&dp[i-1][k]+1>dp[i][j])dp[i][j]=dp[i-1][k]+1;//cout<<"dp"<<i<<"]["<<j<<"]:"<<dp[i][j]<<endl;
                    }
                }
            }
        }
        /*for(int i=1;i<=n;i++)
            for(int j=MIN;j<=MAX;j++)
            cout<<"dp["<<i<<"]["<<j<<"]:"<<dp[i][j]<<endl;*/
        for(int i=MIN;i<=MAX;i++)
        {
            if(dp[n][i]==n)
            {v.push_back(i);break;}
        }
        if(v.size()==0){cout<<"-1"<<endl;return 0;}
        for(int i=n-1;i>=1;i--)
        {
            int flag=1;
            for(int j=MIN;j<=MAX;j++)
            {
                if(dp[i][j]==i)
                {
                    if(j<v[n-i-1]&&a[i]<a[i+1]){v.push_back(j);flag=0;break;}
                    else if(j>v[n-i-1]&&a[i]>a[i+1]){v.push_back(j);flag=0;break;}
                    else if(j!=v[n-i-1]&&a[i]==a[i+1]){v.push_back(j);flag=0;break;}
                }
            }
            if(flag){cout<<"-1"<<endl;return 0;}
        }
        for(int i=v.size()-1;i>=0;i--)
            cout<<v[i]<<" ";
    }
//system("pause");
}

官方題解說的是dp[i][j]表示i位置放j,如果可以過去就令其等於前一個過來的,如果不可以過去就等於-1。[沒大看懂,覺得這樣不可行。]