「LibreOJ β Round #2」DP 一般看规律

题目链接

Description

给定一个长度为 n 的序列 a,一共有 m 个操作。
每次操作的内容为:给定 x,y,序列中所有 x 会变成 y

同时我们有一份代码:

int ans = 2147483647;
for (int i = 1; i <= n; i++) {
    for (int j = i + 1; j <= n; j++) {
        if (a[i] == a[j])
            ans = std::min(ans, j - i);
    }
}
std::cout << ans << std::endl;

请在每次修改后输出代码运行的结果。

Input

第一行两个数,表示 n,m
第二行 n 个数,表示 a1,a2,,an​​。
然后 m 行每行两个数 x y ,表示序列中所有 x 会变成 y

Output

对于每次修改,输出答案。

Sample Input

5 10
2 7 6 3 8
6 1
7 1
1 3
5 6
1 7
9 5
1 10
7 6
7 5
3 9

Sample Output

2147483647
1
1
1
1
1
1
1
1
1

Hint

1n,m100000
每个出现的数字绝对值在 int 范围内。

题目大意

给出操作,将序列中所有一个数字替换为另一个,询问每次操作后距离最近的两个相同数字的距离。

题解

每个数字只与他的前驱和后继产生贡献。构建 n <script id="MathJax-Element-230" type="math/tex">n</script>个set,每次将较小的暴力合并到大的上面,通过lower_bound来找到他的前驱和后继。懒得离散化可以用map来存set。

#include<bits/stdc++.h>
using namespace std;

map< int, set<int> > a;
int n, m, ans = INT_MAX;

void update(int x, int y){
    set<int>::iterator it;
    it = a[x].lower_bound(y);
    if(it != a[x].end()) ans = min(ans, *it - y);
    if(it != a[x].begin()) it--, ans = min(ans, y - *it);
}

void init(){
    scanf("%d%d", &n, &m);
    for(int i = 1, x; i <= n; i++){
        scanf("%d", &x);
        update(x, i);
        a[x].insert(i);
    }
}

void work(){
    for(int i = 1, x1, x2; i <= m; i++){
        scanf("%d%d", &x1, &x2);
        if(x1 == x2){
            printf("%d\n", ans);
            continue;
        }
        if(a[x1].size() > a[x2].size()) swap(a[x1], a[x2]);
        for(set<int>::iterator it = a[x1].begin(); it != a[x1].end(); it++){
            update(x2, *it);
            a[x2].insert(*it);
        }
        a[x1].clear();
        printf("%d\n", ans);
    }
}

int main(){
    init();
    work();
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值