“由于这几道题目有很大的共同点,就放在一起解析”
P1576
此题就是先推出暴力的dp,首先就要想到+1和-1其实是一件事,就是求差值
a[]表示原序列b[]表示排序后的序列
f[i][j]表示把前i个数变成非降序列,并且第i个数变成原序列中从小到大第j个数所用的最少步数。
用g[i][j]表示最优的f[i][j];(i不变)
由于f[][]和g[][]互相传递,所以可以用同一个数组来存储
f[i][j]=min(f[i-1][j]+abs(a[i]-b[j]),f[i][j-1]);
由于空间的问题还要把这个改成滚动数组;
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,a[5001],b[5001];
ll f[5001];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+n+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
f[j]+=abs(a[i]-b[j]);
if(j>1) f[j]=min(f[j],f[j-1]);
}
printf("%lld\n",f[n]);
}
P1697
暴力dp[i][j][k]=min(dp[i-1][j][k]+c[i][k]);dp[i][j][k]=min(dp[i-1][j-1][v],c[i][k])
效率n^3,所以说可以过但是不佳;所以需要优化和上题一样
先用一个 l[i][j][k],r[i][j][k]分别表示k的左端和右端的最优值;
然后互相转移,由于不是自己推的优化,讲解起来并不深入(本人才疏学浅),
希望见谅
#include<bits/stdc++.h>
#define INF 1e14
#define N 105
#define ll long long
using namespace std;
int n,m,Q,k,i,j,a[N],c[N][N],id[N][N];
ll f[N][N][N],l[N][N],r[N][N];
int main(){
scanf("%d%d%d",&n,&m,&Q);
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
scanf("%d",&c[i][j]);
for(i=0;i<=n;i++)
for(j=1;j<=m;j++)
for(k=1;k<=Q;k++)
f[i][j][k]=INF;
for(i=0;i<=n;i++)
for(k=0;k<=Q;k++)
l[i][k]=r[i][k]=INF;
l[0][0]=0;
for(i=1;i<=n;i++) {
for(j=1;j<=m;j++)
for(k=1;k<=Q;k++){
int cost=c[i][j];
if(a[i]==j) cost=0;
if(a[i]!=0&&j!=a[i]) continue;
f[i][j][k]=min(f[i][j][k],f[i-1][j][k]+cost);
if(id[i-1][k-1]==j)
f[i][j][k]=min(f[i][j][k],r[i-1][k-1]+cost);
else
f[i][j][k]=min(f[i][j][k],l[i-1][k-1]+cost);
}
for(k=1;k<=Q;k++)
for(j=1;j<=m;j++){
if(f[i][j][k]<l[i][k]){
r[i][k]=l[i][k];
l[i][k]=f[i][j][k];
id[i][k]=j;
}
else
if(f[i][j][k]<r[i][k])
r[i][k]=f[i][j][k];
}
}
ll ans=INF;
for(i=1;i<=m;i++) ans=min(ans,f[n][i][Q]);
if(ans==INF)printf("-1");
else printf("%lld",ans);
return 0;
}
P2125
这题的优化和上面的雷同,但是效率还是不够(N^3)
所以还是需要加一个hash的比较,用hash离散后的字符串二分比较到最后的
不相同的部分,如果最后还有不同的就二分继续比较,只有一个的时候,就可以直接比较计算答案了
#include<bits/stdc++.h>
#define N 5005
#define mod 1000000007
#define ll long long
using namespace std;
int n,cnt,f[N][N],h[N][N],sum[N][N],ans;
char s[N];
bool cmp(int a, int b, int c, int d) {
if(s[a]!=s[c]) return s[a]>s[c];
if(h[a][b]==h[c][d]) return 0;
int l=1,r=b-a,x=0;
while(l<=r) {
int mid=l+r>>1;
if(h[a][a+mid]==h[c][c+mid])
l=mid+1;
else{
x=mid;
r=mid-1;
}
}
return s[a+x]>s[c+x];
}
int main(){
scanf("%d%s",&n,s+1);
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
h[i][j]=(11LL*(ll)h[i][j-1]+s[j]-'0')%mod;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
sum[i][j]=1;
for(int i=1;i<=n;i++) f[1][i]=1;
for(int i=1;i<=n;i++){
if(s[i]=='0')
for(int j=i;j<=n;j++)
sum[i][j]=sum[i-1][j];
else
for(int j=i;j<=n;j++){
int k=max(i+i-j-1,0);
ll x=(ll)sum[i-1][i-1]-sum[k][i-1];
if(k>0&&cmp(i,j,k,i-1))
x=(x+f[k][i-1])%mod;
if(x<0)x+=mod;
f[i][j]=((ll)f[i][j]+x)%mod;
sum[i][j]=((ll)sum[i-1][j]+f[i][j])%mod;
}
}
printf("%d",sum[n][n]);
return 0;
}