首页 > 其他分享 >2022 Shanghai Collegiate Programming Contest B

2022 Shanghai Collegiate Programming Contest B

时间:2023-04-15 16:45:27浏览次数:55  
标签:vis le Contest int Shanghai Programming 括号 权值 dis

知识点:差分约束

Link:https://codeforces.com/gym/103931/problem/B

被卡 SPFA 了呃呃。

一看出题人是这个人:
如何看待 SPFA 算法已死这种说法? - fstqwq 的回答 - 知乎,那没事了。

简述

给定参数 \(n, q\),表示有一个长度为 \(n\) 的合法括号序列,且有 \(q\) 组限制。每组限制均为 \(l_i, r_i, c_i\) 的形式,表示括号序列区间 \([l_i, r_i]\) 中,左括号数减去右括号数得到的差值为 \(c_i\)。要求判断是否存在一个满足所有限制的合法括号序列,若存在则构造任意一组合法的解。
\(2\le n\le 3000\),\(0\le q\le \min\left( \binom{n+1}{2}, 5\times 10^5\right)\),\(1\le l_i\le r_i\le n\),\(-n\le c_i\le n\)。
2S,1024MB。

分析

给定限制为数量关系,考虑把括号序列合法的条件也抽象成数量关系。记一个左括号的权值为 1,右括号权值为 -1,记 \(s_i\) 表示序列的前缀 \([1, i]\) 的权值之和,则一个长度为 \(n\) 的括号序列合法,则等价于:

  • \(s_0 = s_n = 0\)。
  • \(\forall 1\le i\le n,\ s_i\ge 0\)。
  • \(\forall 1\le i\le n,\ |s_i - s_{i - 1}| = 1\)。

则本题中给定的限制 \((l_i, r_i, c_i)\) 可以表示为 \(s_r - s_{l - 1} = c_i\) 的形式。对于一组满足限制的 \(s\) 的取值,通过差分我们可以唯一确定这组值对应的括号序列。问题变为是否存在一组 \(s\) 的取值满足上述所有限制。

考虑差分约束,记 \(\operatorname{dis}_i\) 表示到达节点 \(i\) 的最短路长度,将上述所有限制转化为三角不等式形式:

  • \(s_0 = s_n = 0\),考虑以节点 0 为起点,且向节点 \(n\) 连一条权值为 0 的边。
  • \(\forall 1\le i\le n,\ s_i\ge 0\),即 \(s_i\ge s_0\),从 \(i\) 向 0 连一条权值为 0 的边。
  • 对于给定限制 \(s_r - s_{l - 1} = c_i\),即 \(c_i \le s_r - s_{l - 1} \le c_i\),从 \(l-1\) 向 \(r\) 连一条权值为 \(c_i\) 的边,从 \(r\) 向 \(l-1\) 连一条权值为 \(-c_i\) 的边。
  • \(\forall 1\le i\le n,\ |s_i - s_{i - 1}| = 1\),可以发现如果 \(q\) 个限制均满足偶数长度的限制区间的 \(c_i\) 为偶数,奇数长度的限制区间的 \(c_i\) 为奇数,则 \(s_{i} \not= s_{i-1}\) 一定成立。则可考虑先判断给定限制是否符合上述条件,再将该条件放松为 \(-1\le s_i - s_{i - 1}\le 1\),从 \(i-1\) 向 \(i\) 连一条权值为 1 的边,从 \(i\) 向 \(i-1\) 连一条权值为 1 的边。

建图后运行差分约束算法,若存在负环则无解,否则根据 \(\operatorname{dis}\) 即可构造一组合法解。

此时如果直接使用 Bellman-Ford/SPFA 算法朴素地实现,则复杂度上界为 \(O(nq)\) 级别,在出题人的特别关照下,使用朴素的 SPFA 算法无法通过本题。

使用 SLF SPFA 可通过本题,且实际运行效率较高。std 则在此基础上采用了一种复杂度稳定的 \(O(n^2)\) 算法,详见下文:


代码

大力 SLF SPFA 爆炒:

//知识点:负环 
/*
By:Luckyblock
*/
// #pragma GCC optimize(2) 
#include <queue>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
const int kN = 3e3 + 10;
const int kM = 5e6 + 10;
//=============================================================
int n, q;
int e_num, head[kN], v[kM], w[kM], ne[kM];
int dis[kN], cnt[kN];
bool vis[kN];
//=============================================================
inline int read() {
  int f = 1, w = 0;
  char ch = getchar();
  for (; !isdigit(ch); ch = getchar())
    if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
  return f * w;
}
void Chkmax(int &fir_, int sec_) {
  if (sec_ > fir_) fir_ = sec_;
}
void Chkmin(int &fir_, int sec_) {
  if (sec_ < fir_) fir_ = sec_;
}
void AddEdge(int u_, int v_, int w_) {
  v[++ e_num] = v_;
  w[e_num] = w_;
  ne[e_num] = head[u_];
  head[u_] = e_num;
}
void Init() {
  e_num = 0;
  memset(head, 0, sizeof (head));
}
bool SpfaBfs(int s_) {
  std::deque <int> q;
  memset(cnt, 0, sizeof (cnt));
  memset(vis, 0, sizeof (vis));
  memset(dis, 63, sizeof (dis));
  q.push_front(s_);
  dis[s_] = 0;
  vis[s_] = true;
  
  while (! q.empty()) {
    int u_ = q.front();
    q.pop_front();
    vis[u_] = false;
    for (int i = head[u_]; i; i = ne[i]) {
      int v_ = v[i], w_ = w[i];
      if (dis[u_] + w_ < dis[v_]) {
        dis[v_] = dis[u_] + w_;
        cnt[v_] = cnt[u_] + 1;
        if (cnt[v_] > n) return true;
        if (! vis[v_]) {
          if (!q.empty() && dis[v_] > dis[q.front()]) q.push_back(v_);
          else q.push_front(v_);
          vis[v_] = true;
        }
      }
    }
  }
  return false;
}
//=============================================================
int main() {
  // freopen("1.txt", "r", stdin);
  n = read(), q = read();
  for (int i = 1; i <= q; ++ i) {
    int l_ = read(), r_ = read(), c_ = read();
    if ((r_ - l_ + 1) % 2 != (abs(c_) % 2)) {
      printf("?\n");
      return 0;
    }
    AddEdge(l_ - 1, r_, c_);
    AddEdge(r_, l_ - 1, -c_);
  }
  for (int i = 1; i <= n; ++ i) {
    AddEdge(i, 0, 0);
    AddEdge(i - 1, i, 1); //(i - 1) <= i + 1
    AddEdge(i, i - 1, 1); //i <= (i - 1) + 1
  }

  AddEdge(0, n, 0);
  if (SpfaBfs(0)) {
    printf("?\n");
    return 0;
  }
  printf("! ");
  for (int i = 1; i <= n; ++ i) {
    // printf("%d ", dis[i]);
    if (dis[i] - dis[i - 1] == 1) {
      printf("(");
    } else {
      printf(")");
    }
  }
  return 0;
}

标签:vis,le,Contest,int,Shanghai,Programming,括号,权值,dis
From: https://www.cnblogs.com/luckyblock/p/17321382.html

相关文章

  • AtCoder Regular Contest 104 D Multiset Mean
    洛谷传送门AtCoder传送门很平凡的一道计数啊。考虑将所有数都减去\(x\),那么就要求选的数和为\(0\)。正负分开考虑,\(0\)可以任意选。需要多重背包求\(f_{i,j}\)表示选\(1\simi\)的数和为\(j\)的方案数。前缀和优化是平凡的。code//Problem:D-MultisetMean......
  • 2012-2013 ACM-ICPC, NEERC, Moscow Subregional Contest题解
    题目链接:2012-2013ACM-ICPC,NEERC,MoscowSubregionalContestC.Cinderella(贪心)思路答案为大于平均值的数的数量代码#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;intmain(){ios::sync_with_stdio(false);cin.tie(nullptr);......
  • HDU 5045 Contest(费用流)
    题目地址:HDU5045终于在比赛中用网络流A了一道题。。。刷了那么多网络流,终于用到一次了。。虽然题目很简单,但是还是要纪念一下下。。。我这题的思路就是求m/n次费用流,每n个算作同一轮,对这同一轮的求最大费用流。建图就很简单了,最简单的二分图模型。代码如下:#include<iostre......
  • Shanghai 2006 / UVa 1382 Distant Galaxy (枚举&扫描&动态维护)
    1382-DistantGalaxyTimelimit:3.000seconds http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=460&page=show_problem&problem=4128YouareobservingadistantgalaxyusingatelescopeabovetheAstronomyTower,......
  • AtCoder Beginner Contest 297
    A-DoubleClick#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongint32_tmain(){intn,d;cin>>n>>d;vector<int>a(n);for(auto&i:a)cin>>i;for(inti=1;i<......
  • AtCoder Beginner Contest 207(D,E)
    AtCoderBeginnerContest207(D,E)D(计算几何)D这个题是两个点的集合,每个集合有\(n\)个点,我们可以让一个集合中的每一个点进行下面两种操作\(1\),可以让每一个点进行旋转\(x\)的角度\(2\),可以让每一个点的\(x\)变成\(x+disx\),\(y\)变成了\(y+disy\)问是否可以让这两个集合......
  • AtCoder Beginner Contest 247(E,F)
    AtCoderBeginnerContest247(E,F)E(思维)E这个题大意就是给一个长度为\(n\)的数组,一个\(x\)和一个\(y\),问这个数组里面可以找到多少段\([l,r]\)满足这一段里面的最大值是\(x\),最小值是\(y\)这里的做法是固定最右端,寻找最左端的可能的数量,最后相加对于每一个位置,都有作为最......
  • AtCoder Regular Contest 127
    D-LIS2难搞的地方在于取min,考虑比较\((a_i\oplusa_j,b_i\oplusb_j)\)两者的过程:是在它们第一位不一样的地方比较,取该位为0的那个。而判断两个数在某位是否相等,可以想到异或操作,然后把这两者异或起来后,由异或运算的交换律可得等价于\((a_i\oplusb_i)\oplus(a_j\oplus......
  • AtCoder Regular Contest 159
    Preface这周六紧张刺激的一日三赛,上午蓝桥杯,晚上ARC之后隔5min就是CF,可谓是手搓键盘到冒烟的一天了这场其实打的感觉很没水准,B刚开始没想清楚很多边界条件挂了三发,45min左右才过然后C的构造也不太会,随便写了个暴力也是挂挂挂,只好弃了去写D题了结果发现D题好像是个不难的线段树......
  • 练习记录- AtCoder Beginner Contest 295(D)
    vp的觉得我的D很聪明所以来写一下(乐D-ThreeDaysAgo题意就是求所有字符出现次数均为偶数的字串数量太笨了所以想了很久我把存在奇数个1当作第2位是2那么当经过了两次1 2^2这个2就变成了02就是第二位就是4...以此类推 所以我遍历一遍字符串求出当前的异或......