Codeforces425C Sereja and Two Sequences

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; 
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值