大意:给你一串只有1,2的数字,让你改变最少的次数,让这个序列变成非递减的。
先开始看这个题目,完全不会做,去网上百度了一下,居然说这个题是求最长非递减子序列的长度,但是用nlogn算法求非严格递增的子序列长度我不会,只能另想办法。在网上搜到了一个神码,我现在都不知道为什么:
#include<cstdio>
int i,n,a,f[3]={0};
int main()
{
scanf("%d",&n);
for(i=0;i<n;++i)
{
scanf("%d",&a),++f[a];
if(f[2]<f[1])f[2]=f[1];
}
printf("%d\n",n-f[2]);
}
后来我自己想了一个。
开一个dp[30010][3]的数组
其中dp[i][j]表示把第i个数改成j最少要花多少次
那么状态转移方程就列出来了:
令a=1 j!=a[i]
0 j==a[i]
那么dp[i][1]=dp[i-1][1]+a;
dp[i][2]=min(dp[i-1][1],dp[i-1][2])+a;
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 30010
int dp[MAXN][3];
int min(int a,int b)
{
return a>b?b:a;
}
int main(void)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int a;
scanf("%d",&a);
int b=(a==1?0:1);
dp[i][1]=dp[i-1][1]+b;
b=!b;
dp[i][2]=min(dp[i-1][1],dp[i-1][2])+b;
}
printf("%d\n",min(dp[n][1],dp[n][2]));
}
poj 3670 也和这个类似,只是有1,2,3数,然后递减也可以:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 30010
int dp[MAXN][4];
int dp2[MAXN][4];
int min(int a,int b)
{
return a>b?b:a;
}
int main(void)
{
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
int a;
scanf("%d",&a);
int b=(a==1?0:1);
int c=(a==3?0:1);
dp[i][1]=dp[i-1][1]+b;
dp2[i][3]=dp2[i-1][3]+c;
b=(a==2?0:1);
int m=min(dp[i-1][1],dp[i-1][2]);
int n=min(dp2[i-1][3],dp2[i-1][2]);
dp[i][2]=m+b;
dp2[i][2]=n+b;
m=min(m,dp[i-1][3]);
n=min(n,dp2[i-1][1]);
b=(a==3?0:1);
c=(a==1?0:1);
dp[i][3]=m+b;
dp2[i][1]=c+n;
}
int m=min(dp[t][2],dp[t][1]);
m=min(m,dp[t][3]);
int n=min(dp2[t][1],dp2[t][2]);
n=min(n,dp2[t][3]);
printf("%d\n",min(m,n));
}