codeforces 425C

时间:2023-03-09 22:30:41
codeforces 425C

题意:给定长度为n,m<=100000的范围在100000以内的数组a,b。

现在给定两种操作:

第一种是ai,bj相等,ai,bj之前的数全删掉,费用为e,收益为1

第二种是把剩下的全部删掉,花费为之前删除的数的个数,并且得到的之前的收益(也就是必须这一步,不然1的收益都无效)

思路:刚开始看错题意了。。以为第二种操作花费为剩下的个数。。

然后多写了一段。。。还wa了。。虽然思路差不多。。

那么题目等价与a,b数组中找到最多的不相交线段。。

但是单纯这样还是要跪。。注意到s/e<=300,那么就可以二维dp

f[i][j]表示做到a[i],有j对不相交线段的最近额b数组出现在什么位置。。

那么做法就很像不下降子序列nlogn版本的做法了。。

具体看代码吧。。

code:

 #include <bits/stdc++.h>
using namespace std;
#define vii vector<int>::iterator
#define M0(a) memset(a, 0, sizeof(a))
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
int a[], b[], n, m, s, e;
int f[];
vector<int> p[]; void init(){
repf(i, , n) scanf("%d", &a[i]);
repf(i, , m) scanf("%d", &b[i]);
for (int i = ; i <= ; ++i) p[i].clear();
repf(i, , m) p[b[i]].push_back(i);
} void solve(){
int t = s / e;
// cout << t << endl;
for (int i = ; i <= t; ++i) f[i] = m+;
f[] = ;
int ans = ;
for (int i = ; i < n; ++i){
for (int j = t; j >= ; --j) if (f[j] <= m){
vii it = upper_bound(p[a[i+]].begin(), p[a[i+]].end(), f[j]);
if (it != p[a[i+]].end()) f[j+] = min(f[j+], *it);
}
for (int j = ; j <= t; ++j) if (f[j] <= m)
if (j * e + f[j] + i + <= s) ans = max(ans, j);
}
cout << ans << endl;
} int main(){
// freopen("a.in", "r", stdin);
while (scanf("%d%d%d%d", &n, &m, &s, &e) != EOF){
init();
solve();
}
}