P3558 [POI2013]BAJ-Bytecomputer题解
题型考察
此题是经典的最优解问题,考虑贪心或 \(\text{DP}\) 解决。贪心似乎不可行,因此考虑 \(\text{DP}\)。
在序列上首先考虑线性 \(\text{DP}\)。
思路
首先按照常规思路,\(\text{DP}\) 的第一个维度表示当前到第几个数,即 \(dp[i]\) 表示 \(a[1 \dots i]\) 的最优解。接下来考虑其他维度,在转移过程中无论是从哪转移还是转移到哪里,都是和 \(a\) 数组的值相关,考虑第二维度表示当前位置的数值在三种情况下分别的最优解。因此状态设计更新为 \(dp[i][j]\) 表示 \(a[1 \dots i]\) 且 \(a[i]=j+1\) 的最优解。(加一是为了避免负数下标)。此时状态设计结束。
处理边界值,作为数组的第一个数,无论怎么对数组中的数字进行操作,\(a[1]\) 的值始终不变,故有:
dp[1][0]=dp[1][1]=dp[1][2]=inf;
dp[1][a[1]+1]=0;
\(inf\) 是大常数,起到无穷大的作用。此刻初始化结束。
考虑状态转移方程。作为 \(\text{DP}\) 的核心,通常要在不同的条件下明确由谁到谁的转移。一般化的,当前要转移得到的对象为 \(dp[i][j]\)。
当 \(a[i]=-1\) 时
//cmin(a,b,c)=min(a,min(b,c))
dp[i][0]=dp[i-1][0];//不需要有转移代价+遵循单调不降(dp[i][1]与dp[i][2]便不参与本次转移)
if(a[i-1]==1) dp[i][1]=min(dp[i-1][0],dp[i-1][1])+1;//此时转移代价为1次+遵循单调不降(dp[i][2]便不参与本次转移)
else dp[i][1]=inf;//此时无法转移
if(a[i-1]==1) dp[i][2]=cmin(dp[i-1][0],dp[i-1][1],dp[i-1][2])+2;//此时转移代价为2次+遵循单调不降(统统参与本次转移)
else dp[i][2]=dp[i-1][2]+2;//此时转移代价为2次+遵循单调不降(特殊条件,dp[i][0]与dp[i][1]便不参与本次转移)
按照此思路,同理可得。
当 \(a[i]=0\) 时
dp[i][0]=dp[i-1][0]+1;
dp[i][1]=min(dp[i-1][0],dp[i-1][1]);
if(a[i-1]==1) dp[i][2]=cmin(dp[i-1][0],dp[i-1][1],dp[i-1][2])+1;
else dp[i][2]=dp[i-1][2]+1;
当 \(a[i]=1\) 时
dp[i][0]=dp[i-1][0]+2;
if(a[i-1]==-1) dp[i][1]=min(dp[i-1][0],dp[i-1][1])+1;
else dp[i][1]=dp[i-1][0]+1;
dp[i][2]=cmin(dp[i-1][0],dp[i-1][1],dp[i-1][2]);
此刻状态转移方程结束。
目标状态,对于此题,可以发现答案为
ans=cmin(dp[n][0],dp[n][1],dp[n][2]);
另外如果 \(ans\) 大于等于 \(inf\) 就输出 \(BRAK\)。
代码实现
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1000010;
const int inf=1e9;
int n,ans;
int a[N],dp[N][3];
int cmin(int x,int y,int z) {
return min(x,min(y,z));
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
dp[1][0]=dp[1][1]=dp[1][2]=inf;
dp[1][a[1]+1]=0;
for(int i=2;i<=n;i++) {
if(a[i]==-1) {
dp[i][0]=dp[i-1][0];
if(a[i-1]==1) dp[i][1]=min(dp[i-1][0],dp[i-1][1])+1;
else dp[i][1]=inf;
if(a[i-1]==1) dp[i][2]=cmin(dp[i-1][0],dp[i-1][1],dp[i-1][2])+2;
else dp[i][2]=dp[i-1][2]+2;
}
else if(a[i]==0) {
dp[i][0]=dp[i-1][0]+1;
dp[i][1]=min(dp[i-1][0],dp[i-1][1]);
if(a[i-1]==1) dp[i][2]=cmin(dp[i-1][0],dp[i-1][1],dp[i-1][2])+1;
else dp[i][2]=dp[i-1][2]+1;
}
else {
dp[i][0]=dp[i-1][0]+2;
if(a[i-1]==-1) dp[i][1]=min(dp[i-1][0],dp[i-1][1])+1;
else dp[i][1]=dp[i-1][0]+1;
dp[i][2]=cmin(dp[i-1][0],dp[i-1][1],dp[i-1][2]);
}
}
ans=cmin(dp[n][0],dp[n][1],dp[n][2]);
if(ans>=inf) cout<<"BRAK";
else cout<<ans;
return 0;
}

浙公网安备 33010602011771号