题意:
两组数字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)-1
int 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;
}