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。[没大看懂,觉得这样不可行。]

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值