題意
你有一個有序的數組,現在要插入一個新的數,相信你一定學過二分查找,也知道最壞情況下需要比較幾次才能找到新的數該插入什麼位置,但是現在,我們稍微改變下套路,把新的數與數組中的每一個數比較都會有一個特定的代價,代價在1-9之間,求最壞情況下,假設你採用最優的比較策略,你會花費多少費用插入新的數。
數據範圍
有組數據,數組大小
解法
首先考慮一個常規的區間dp:
轉移:
這樣做是的,一般來見似乎沒有什麼辦法優化,但是我們發現最終答案非常的小,所以考慮換一種dp狀態:
轉移就也是把兩個區間拼起來
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
inline int read(){
char c=getchar();int t=0,f=1;
while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
while((isdigit(c))&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int t,n,a[maxn],at[maxn][10],las[maxn],f[maxn][200];
char s[maxn];
signed main(){
t=read();
for(int x=1;x<=t;x++){
scanf("%s",s+1);n=strlen(s+1);
memset(f,0,sizeof(f));memset(las,0,sizeof(las));
for(int i=1;i<=n;i++){
a[i]=s[i]-'0';
}
for(int i=1;i<=n;i++){
las[a[i]]=i;
for(int j=1;j<=9;j++)at[i][j]=las[j];//at是序列自動機
}
for(int i=1;i<=n+1;i++){
for(int j=0;j<=180;j++){
f[i][j]=i-1;
}
}
for(int i=n;i>=1;i--){//倒着轉移
for(int j=1;j<=180;j++){
f[i][j]=f[i][j-1];
for(int d=1;d<=min(j,9);d++){
int p=at[f[i][j-d]+1][d];
if(p<i)continue;
f[i][j]=max(f[i][j],f[p+1][j-d]);
}
}
}
for(int i=0;i<=180;i++)
if(f[1][i]==n){printf("Case #%d: %d\n",x,i);break;}
}
return 0;
}