@ysner
2018-08-03T18:11:50.000000Z
字数 1945
阅读 2785
DP
给一个只包含的数列,每次操作可以让,求最少操作次数使得序列单调不降。
显然只能设状态表示已处理完第个数,第个数转化为的最小操作次数。
本题难度在于考虑转移条件。
话说我一开始是这么写的:(充分体现了我蒟蒻的本质)
fp(i,0,n) dp[i][0]=dp[i][1]=dp[i][2]=inf;dp[1][a[1]+1]=1;fp(i,2,n){if(a[i]==-1){dp[i][0]=dp[i-1][0];//dp[i][1]=dp[i-1][2];dp[i][2]=dp[i-1][2]+2;}if(a[i]==0){dp[i][0]=dp[i-1][0]+1;dp[i][1]=dp[i-1][1];dp[i][2]=dp[i-1][2]+1;}if(a[i]==1){dp[i][0]=dp[i-1][0]+2;dp[i][1]=dp[i-1][0]+1;dp[i][2]=dp[i-1][2];}}re ll ans=min(dp[n][0],min(dp[n][1],dp[n][2]));
然后答案大了很多。
那应该怎样转移呢?
至于一些细节如取、对答案的贡献等自己想想吧。
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<algorithm>#include<vector>#define re register#define il inline#define ll long long#define inf 1e18#define max(a,b) ((a)>(b)?(a):(b))#define min(a,b) ((a)<(b)?(a):(b))#define fp(i,a,b) for(re int i=a;i<=b;i++)#define fq(i,a,b) for(re int i=a;i>=b;i--)using namespace std;const int mod=1e9+7,N=1e6+100;ll dp[N][3],n,a[N];il ll gi(){re ll x=0,t=1;re char ch=getchar();while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();if(ch=='-') t=-1,ch=getchar();while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();return x*t;}int main(){n=gi();fp(i,1,n) a[i]=gi();fp(i,0,n) dp[i][0]=dp[i][1]=dp[i][2]=inf;dp[1][a[1]+1]=0;fp(i,2,n){if(a[i]==-1){dp[i][0]=dp[i-1][0];dp[i][1]=(a[i-1]==1)?min(dp[i-1][0],dp[i-1][1])+1:inf;dp[i][2]=(a[i-1]==1)?min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]))+2:dp[i-1][2]+2;}if(a[i]==0){dp[i][0]=dp[i-1][0]+1;dp[i][1]=min(dp[i-1][1],dp[i-1][0]);dp[i][2]=(a[i-1]==1)?min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]))+1:dp[i-1][2]+1;}if(a[i]==1){dp[i][0]=dp[i-1][0]+2;dp[i][1]=(a[i-1]==-1)?min(dp[i-1][0],dp[i-1][1])+1:dp[i-1][0]+1;dp[i][2]=min(dp[i-1][0],min(dp[i-1][1],dp[i-1][2]));}}re ll ans=min(dp[n][0],min(dp[n][1],dp[n][2]));if(ans>=inf) puts("BRAK");else printf("%lld\n",ans);return 0;}
