http://codeforces.com/problemset/problem/425/C
Sereja has two sequences a1, a2, …, an and b1, b2, …, bm, consisting of integers. One day Sereja got bored and he decided two play with them. The rules of the game was very simple. Sereja makes several moves, in one move he can perform one of the following actions:

Choose several (at least one) first elements of sequence a (non-empty prefix of a), choose several (at least one) first elements of sequence b (non-empty prefix of b); the element of sequence a with the maximum index among the chosen ones must be equal to the element of sequence b with the maximum index among the chosen ones; remove the chosen elements from the sequences.
Remove all elements of both sequences.
The first action is worth e energy units and adds one dollar to Sereja’s electronic account. The second action is worth the number of energy units equal to the number of elements Sereja removed from the sequences before performing this action. After Sereja performed the second action, he gets all the money that he earned on his electronic account during the game.

Initially Sereja has s energy units and no money on his account. What maximum number of money can Sereja get? Note, the amount of Seraja’s energy mustn’t be negative at any time moment.

Input
The first line contains integers n, m, s, e (1 ≤ n, m ≤ 105; 1 ≤ s ≤ 3·105; 103 ≤ e ≤ 104). The second line contains n integers a1, a2, …, an (1 ≤ ai ≤ 105). The third line contains m integers b1, b2, …, bm (1 ≤ bi ≤ 105).

Output
Print a single integer — maximum number of money in dollars that Sereja can get.

题意:两数列a[],b[],进行若干***作,每次操作花费e,将a的一个前缀和b的一个前缀(两前缀的最后一个数字必须相同)删除,并得到虚拟1元,最后的一次操作是将剩下的a[],b[]全部清空,花费是之前把a[],b[]删除的总数字个数,使得虚拟ans元变为真实ans元。

思路:看到这个应该明显是一个求LCS,并对于每一个f(i,j)判断一下是否花费小于等于s。但是复杂度nm=10^10没办法做。
朴素的LCS是f(i,j):a的前i个,b的前j个,构成的最长公共子序列长度。注意到这道题s/e最大只有300,也就是LCS长度最大只取300,那么我们改一下LCS的三个因素,设f(i,j):LCS长度为i,并且a取前j个,对应的b最少取前f(i,j)个,这个过程要用二分,这样复杂度就是300nlogn,差不多10^8,这样就解决了问题。
综上所述,这道题设f(i,j):得到i元钱,a取前j个,对应的b最少取前f(i,j)个。
f(i,j)=min{f(i,j-1),在f(i-1,j-1)之后查找到第一个等于a[j]的位置}

#include<bits/stdc++.h>
using namespace std;
#define maxn 100000+100
#define INF 0x3f3f3f3f

int n,m,s,e,a[maxn],b[maxn],ans;
vector<int> idx[maxn];
int f[305][maxn];

void debug()
{
    for(int i=1;i<=s/e;i++)
    {
        printf("%d:",i);
        for(int j=1;j<=n;j++)
        printf("[%d]=%d,",j,f[i][j]);
        puts("");
    }
}

int main()
{
    //freopen("input.in","r",stdin);
    cin>>n>>m>>s>>e;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int j=1;j<=m;j++)scanf("%d",&b[j]),idx[b[j]].push_back(j);
    for(int i=1;i<=n;i++)idx[a[i]].push_back(INF);

    for(int i=1;i<=s/e;i++)f[i][0]=INF;
    memset(f[0],0,sizeof(f[0]));
    for(int i=1;i<=s/e;i++)
    {
        for(int j=1;j<=n;j++)
        {
            int k=lower_bound(idx[a[j]].begin(),idx[a[j]].end(),min(f[i-1][j-1]+1,INF))-idx[a[j]].begin();
            f[i][j]=min(idx[a[j]][k],f[i][j-1]);
            if(j+f[i][j]+i*e<=s)ans=i;
        }
    }   
    ///debug();
    cout<<ans<<endl;
    return 0; 
}