CodeForces Problem - Segments Removal

CodeForces Problem - Segments Removal

原题地址

题目类型:链表、Set
题意

给定一个整数序列,每次选择元素相同的最长的连续的子串然后删除,删除后左右两边的部分会拼接起来,如果有多个这样的子串则选择最左边的。求按照如上规则多少次操作后源串会变为空串。

分析

首先将连续的子串处理为 numcnt 表示,然后用静态链表存储,并用 TreeSet 保存,使得 set 最后一个元素为长度最长且是最左边得子串。然后模拟执行上面得操作,每次删除一个子串后将其链表中左右两边得节点连起来,并判断是否相同,如果相同则进行合并,并更新 set 中得值。

代码
static int[] r;
static int[] l;
static int[] cnt;
static int[] num;
static boolean[] vis;
static int idx;
static TreeSet<Node> q;
public static void solve() throws IOException {
    int n = nextInt();
    
    init(n);
    
    int[] a = new int[n];
    
    for (int i = 0; i < n; i++) a[i] = nextInt();
    
    q = new TreeSet<>();
    
    for (int i = 0; i < n; i++) {
        int j = i;
        while (j + 1 < n && a[i] == a[j + 1]) j++;
        q.add(new Node(j - i + 1, idx));
        add(a[i], j - i + 1);
        i = j;
    }
    
    int ans = 0;
    while (!q.isEmpty()) {
        Node e = q.last();
        q.remove(e);
        
        if (vis[e.idx] || e.cnt == 0) continue;
        
        ans++;
        remove(e.idx);
    }
    pw.println(ans);
} 

public static void remove(int k) {
    vis[k] = true;
    r[l[k]] = r[k];
    l[r[k]] = l[k];
    k = l[k];
    
    if (num[k] == num[r[k]]) {
        q.remove(new Node(cnt[k], k));
        vis[r[k]] = true;
        cnt[k] += cnt[r[k]];
        r[k] = r[r[k]];
        l[r[k]] = k;
        q.add(new Node(cnt[k], k));
    }
    
}

public static void add(int x, int c) {
    num[idx] = x;
    cnt[idx] = c;
    r[idx] = idx + 1;
    l[idx] = idx - 1;
    idx++;
}

public static void init(int n) {
    int N = 200010;
    vis = new boolean[N];
    r = new int[N];
    l = new int[N];
    cnt = new int[N];
    num = new int[N];
    idx = 2;
}

/*****************************************************************************************/

static class Node implements Comparable<Node>{
    int cnt;
    int idx;
    
    public Node(int cnt, int idx) {
        this.cnt = cnt;
        this.idx = idx;
    }
    
    @Override
    public int compareTo(Main.Node o) {
        if (this.cnt != o.cnt) return this.cnt - o.cnt;
        else return o.idx - this.idx;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值