C. Playing Piano
阿新 • • 發佈:2019-02-14
題解:
對於原來的序列把它對應換成新的序列。
新序列保證:同增 同減 相同元素處兩元素不同。(原序列相同)
對於新序列:遞迴出來選擇。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。[沒大看懂,覺得這樣不可行。]