標籤:codeforces dp
題意:
兩組數字a和b 如果a[i]等於b[j] 則可將a[i]和b[j]前所有數字刪掉 這種操作花費e體力 得到1元錢 或者一次刪掉所有數字 這種操作花費等於曾經刪除的所有數字個數 做完後得到所有錢 問 一共s體力 可以得到多少錢
思路:
dp+二分
由資料可知最多拿到300元錢 因此可以定義 dp[i][j]表示有i元錢時 b串刪除到了j處時 a串刪到的位置
狀態轉移為 dp[i][j] = lower_bound ( a[j] , dp[i-1][j-1] + 1 ) 意思是a[j]與dp[i-1][j-1]後的第一個相同的數字匹配 (可以這麼做的原因是 保證第二種操作的花費最小 同時留下盡量多的數字供後面使用)
代碼:
#include<cstdio>#include<cstring>#include<algorithm>#include<vector>using namespace std;#define N 100010#define inf (1U<<31)-1int n,m,s,e,ans;int a[N],b[N],dp[305][N];vector<int> ed[N];int main(){ int i,j,k; scanf("%d%d%d%d",&n,&m,&s,&e); for(i=1;i<=n;i++) scanf("%d",&a[i]); for(j=1;j<=m;j++) { scanf("%d",&b[j]); ed[b[j]].push_back(j); } for(i=0;i<N;i++) ed[i].push_back(inf); memset(dp,-1,sizeof(dp)); memset(dp[0],0,sizeof(dp[0])); for(i=1;i<=s/e;i++) { for(j=1;j<=n;j++) { if(dp[i-1][j-1]!=-1) { dp[i][j]=dp[i][j-1]; k=lower_bound(ed[a[j]].begin(),ed[a[j]].end(),dp[i-1][j-1]+1)-ed[a[j]].begin(); k=ed[a[j]][k]; if(k==inf) continue; if(dp[i][j]==-1||dp[i][j]>k) dp[i][j]=k; if(dp[i][j]+j+i*e<=s) ans=max(ans,i); } } } printf("%d\n",ans); return 0;}